面向对象的精髓:将数据和处理数据的代码绑定成一个对象

只要获取到对象相应的数据和方法都有了

一.组合

什么叫组合?

多个对象放在一起叫组合

组合的作用也是降低代码的冗余

# 学生会增加各种各样的新的属性 比如手机 比如电脑, 这样Student中会增加大量的属性和方法
# 后期的维护成本非常高
# 这时就需要使用组合 来完成减少代码冗余
class Phone:
  def __init__(self,phonenumber,operator,address):
    self.phonenumber=phonenumber
    self.operator=operator
    self.address=address
  def call(self):
    print('%s 正在拨号!'% self.phonenumber)
class Person:
  def __init__(self,name,sex,age):
    self.name=name
    self.sex=sex
    self.age=age

class Student(Person):
  def __init__(self,name,sex,age,number):
    super().__init__(name,sex,age)
    self.number=number
  def show_info(self):
    print(self.__dict__)
  def select_cursor(self):
    print('%s正在选课'% self.name)
class Teacher(Person):
  def __init__(self,name,sex,age,salary,level):
    super().__init__(name,sex,age)
    self.salary=salary
    self.level=level
  def set_score(self):
    print('%s 正在给学生打分'% self.name)
stu1=Student('henry','man','29','3')
p1=Phone('18888888888','中国移动','山西运城')
stu1.phone=p1
stu1.phone.call()
# 通过将手机对象和学生对象进行组合 完成了需求,并且相比较继承而言
# 耦合度低 手机和学生在修改的时候 互不影响
# 同时也减少了代码冗余
# 组合是 对象之间的关系 学生对象拥有手机对象

小练习:
"""
用代码 描述乐队
一个乐队有乐队名,主唱以及其他乐器组成
乐队可以演奏歌曲

主唱是歌手类 会唱歌 ,有名字
钢琴类 能弹奏,有价格,牌子
"""
class Band:
  def __init__(self,name,singer,piano):
    self.name = name
    self.singer = singer
    self.piano = piano

  def play_music(self):
    print("hello 我们%s 组合! 请欣赏" % self.name)
    self.singer.singing()
    self.piano.playing()
class Singer:
  def __init__(self,name):
    self.name = name

  def singing(self):
    print("你好我是歌手 ",self.name)

class Piano:
  def __init__(self,price,brand):
    self.price = price
    self.brand = brand

  def playing(self):
    print("正在弹琴.....")

# 发现一个歌手
singer = Singer("刘宪华")
# 买一台钢琴
p = Piano("100000000","雅马哈")

# 组件乐队
b = Band("F4",singer,p)

# 开演唱会
b.play_music()

二、面向对象的三大特征之封装

1.什么是封装?

在程序中封装指的是将内容隐藏起来,在面向对象中就是将属性和方法隐藏起来

注意:封装不是单纯的隐藏

封装是指:隐藏内部实现细节,对外提供使用接口

2.为什么封装?

①提高安全性 对封装而言是通过给访问和修改增加额外的逻辑判断来实现的

②封装是为了明确区分内部和外部

3.如何使用封装?

在属性或方法名称前加两个下滑线,就可以为将其设置为私有的

python中权限只有两种,公开的和私有的

属性的封装 需要提供相应 的设置器和访问器

4.封装的特点?

被隐藏的内容 在内部可以直接访问,外部无法访问

总结:对于被隐藏的属性 访问和修改需要通过方法 get用于获取 set用于设置(也称之为设置器和访问器)

5.封装方法的好处

①提高安全性

②隔离复杂度 (将复杂的内容隔离到内部 外部只留下简单的接口 对于使用者难度降低)

class ATM:
  def __insert_card(self):
    print('请插入银行卡...')
  def __input_pwd(self):
    print('请输入密码...')
  def __select_money(self):
    print('请输入取款金额...')
  def withdraw(self):
    self.__insert_card()
    self.__input_pwd()
    self.__select_money()
    print('取款成功!')
atm=ATM()
atm.withdraw()
print(ATM.__dict__)

6.封装的实现原理

class Person:
  def __init__(self,name,sex,age,id_card):
    self.name=name
    self.sex=sex
    self.age=age
    self.__id_card=id_card
  def get_id_card(self,pwd):
    if pwd == '123':
      return self.__id_card
    else:
      print('你无法查看我的身份证信息!')
  def set_id_card(self,pwd,new_id_card):
    if pwd == '123':
      self.__id_card=new_id_card
    else:
      print('你没有资格修改我的身份证号!')
p1=Person('henry','man',24,'123487349830495584')
print(p1.__dict__)
#结果:{'name': 'henry', 'sex': 'man', 'age': 24, \
'_Person__id_card': '123487349830495584'}

print(p1.get_id_card('123'))
p1.set_id_card('123','142346199810183456')
print(p1.get_id_card('123'))

通过__dict__可以发现
#1.私有属性和方法名称 前自动加上了_类名 python就是通过这种装换的方式来实现封装的
#2.只有在类的内部的双下滑线才能被自动转换,并且这个转换的过程只能执行一次,在类定义完成后后续添加的双下划綫开头的名称是不会自动转换的
p1.__id_card='xxxxx'
print(p1.__id_card) #结果:xxxxx
print(p1.get_id_card('123')) #结果:123487349830495584
#3.父类中私有的方法,子类中无法使用
class A:
  def __f1(self):
    print("A __f1")

class B(A):
  def __f2(self):
    self.__f1()
    print("B __f2")

  def test(self):
    self.__f2()

b = B()
b.test()
#结果:报错:'B' object has no attribute '_B__f1'

#在父类中定义的私有方法,子类中无法覆盖
class A:
  def f(self):
    self.__f1()
  def __f1(self):
    print('A __f1')
class B(A):
  def __f1(self):
    print('B __f1')
  def f2(self):
    self.f()
b=B()
b.f2()
#结果:A __f1
之所以无法覆盖是因为子类和父类中的私有方法名称必然不相同 子类的方法一定是子类独有的 所以无法覆盖

7.property装饰器

BMI案例:
class Person:
  def __init__(self,name,weight,height):
    self.name=name
    self.weight=weight
    self.height=height
  def bmi(self):
    return self.weight/(self.height*self.height)
p1=Person('henry',69,1.76)
print(p1.bmi())
p1.weight+=2
print(p1.bmi())

当一些属性的值 不是固定的而是通过计算得来的时候 我们必须为这个属性增加方法才能完成计算
但是一旦使用方法后 该属性的访问就变成了方法的调用 很明显与其他的属性访问方式不同,这样给使用者造成迷惑
所以需要将这个方法伪装成普通属性 这就用到了property装饰器
我们可以对上述BMI代码进行装饰,将使用方法调用伪装成属性的访问
class Person:
  def __init__(self,name,weight,height):
    self.name=name
    self.weight=weight
    self.height=height
  @property
  def bmi(self):
    return self.weight/(self.height*self.height)
p1=Person('henry',69,1.76)
print(p1.bmi)
p1.weight+=2
print(p1.bmi)

property可以将方法伪装成属性 利用这个特点 我们也可以将其使用到封装中
这时候就可以使用property来进行伪装 使得访问私有属性与访问普通属性的方式一致
property还提供了 setter(用于修改属性的值) 和 deleter(删除属性的值)

class Person:
  def __init__(self,name,sex,age,id_card):
    self.name=name
    self.sex=sex
    self.age=age
    self.__id_card=id_card
  @property
  def id_card(self):
    return self.__id_card
  @id_card.setter
  def id_card(self,new_id_card):
    self.__id_card=new_id_card
  @id_card.deleter
  def id_card(self):
    del self.__id_card
    print('身份证已删除!')

p1=Person('henry','man',24,'123487349830495584')
print(p1.id_card) #结果:123487349830495584

p1.id_card='aaaaaaa'
print(p1.id_card) #结果:aaaaaaa

del p1.id_card
print(p1.__dict__) #结果:{'name': 'henry', 'sex': 'man', 'age': 24}

三、面向对象三大特征之多态

1.什么是多态?

一种事物具备多种形态或者状态 称之为多态

官方解释:不同对象,可以相对应同一方法,并做出不同的行为,产生不同的结果

2.如何实现多态?

让几个不同类拥有相同的父类,这样一来他们就具备了相同的方法,每个子类要覆盖父类的方法,从而每个类的对象行为都不同.

class Phone:
  def call(self):
    print("手机就能打电话..")
  def send_msg(self):
    print("手机能发短信..")

class WindowsPhone(Phone):
  def call(self):
    print("拨号打电话..")
  def send_msg(self):
    print("输入号码发短信..")

class IPhone(Phone):
  def call(self):
    print("拨号打电话..")
  def send_msg(self):
    print("输入号码发短信..")

#可以定义一个方法接受一个手机为参数 无论是是类型的手机 都可以被使用
def CALL(phone):
  phone.call()

wp = WindowsPhone()
ipx = IPhone()

CALL(wp)
CALL(ipx)
当使用了多态之后 对象的使用者不需要关系这个对象具体的实现,只需要知道该对象属于哪个基类,就能直接使用它
如此扩展性变高了

3.多态之abc模块

多态是多个类的对象拥有相同的方法,但是我们没有从严格要求说必须提供这些方法,子类完全可以不提供这些方法
# 现在要做的就是 严格要求 子类必须实现父类声明的方法
import abc
# abstract class 是抽象类的缩写 抽象的意思是 不清晰 不具体 看不懂

#使用ABC模块来限制子类 的步骤
#1.为类中指定源类为abc.ABCMeta
#2.在相应的方法上加上abc.abstractmethod装饰器

import abc
# 电脑基类
class Computer(metaclass=abc.ABCMeta):

  @abc.abstractmethod
  def open(self):
    pass

  @abc.abstractmethod
  def shutdown(self):
    pass

class DesktopComputer(Computer):
  def open(self):
    print("台式机正在启动....")

  def shutdown(self):
    print("台式机正在关机....")

class Worker:

  def working(self,pc):
    # 先开机
    pc.open()
    print("工作中.....")
    pc.shutdown()

w1 = Worker()

dp = DesktopComputer()

w1.working(dp)

# 增加了笔记本电脑
class BookComputer(Computer):

  def open(self):
    print("笔记本正在启动....")

  def shutdown(self):
    print("笔记本正在关机....")

bc = BookComputer()
w1.working(bc)

class PadComputer(Computer):

  def open(self):
    print("平板正在启动....")

  def shutdown(self):
    print("平板正在关机....")

bc = PadComputer()
w1.working(bc)

4.鸭子类型

python推崇简单的编程方式
鸭子类型 如果一个对象叫声像鸭子 走路也想鸭子 那就把它当成鸭子
对应到代码中就是: 只要你的行为一样 那就把你当成同一个类型来看待
class Duck:
  def bark(self):
    print("鸭子嘎嘎叫...")

  def run(self):
    print("摇摇晃晃走....")

class Chicken:
  def bark(self):
    print("鸡咯咯叫...")

  def run(self):
    print("摇摇晃晃走....")

def test(obj):
  obj.bark()
  obj.run()
duck = Duck()
c = Chicken()

test(duck)
test(c)
如果你足够自觉 你可以不使用abc模块 也不需要基类 自觉地将方法名字都写成一样 同样可以实现多态
这种方式称之为鸭子类型

day24,25组合 封装 多态的更多相关文章

  1. 面向对象之 组合 封装 多态 property 装饰器

    1.组合 什么是组合? 一个对象的属性是来自另一个类的对象,称之为组合 为什么要用组合 组合也是用来解决类与类代码冗余的问题 3.如何用组合 # obj1.xxx=obj2''''''# class ...

  2. Python学习day25-面向对象之组合,多态和封装

    figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...

  3. 面向对象(三)——组合、多态、封装、property装饰器

    组合.多态.封装.property装饰器 一.组合 1.什么是组合 组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象 class Foo(): pass class Bar(): pas ...

  4. python之面向对象性封装,多态,以及鸭子类型

    默认类型 class A: class_name = 'python23期' def __init__(self, name, age): self.name = name self.age =age ...

  5. OOP面向对象 三大特征 继承封装多态

    OOP面向对象 ----三大特征 继承封装多态 面向对象(Object Oriented,OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构 ...

  6. Python进阶(十六)----面向对象之~封装,多态,鸭子模型,super原理(单继承原理,多继承原理)

    Python进阶(十六)----面向对象之~封装,多态,鸭子模型,super原理(单继承原理,多继承原理) 一丶封装 , 多态 封装:            将一些东西封装到一个地方,你还可以取出来( ...

  7. java 封装多态继承

    java 面向对象思想 封装多态继承 面向过程与面向对象 编程分为面向对象编程和面向对象编程,汇编,C语言是面向过程写代码,C++/Java是面向对象 其实面向过程和面向对象在本质都是一样写代码,然后 ...

  8. 组合,多态与多态性,封装以及property装饰器介绍

    一:组合: 什么是组合:组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象. 为何要用组合:通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合 ...

  9. 组合+封装+property+多态+鸭子类型(day21)

    目录 昨日回顾 继承 什么是继承 继承的目的 什么是抽象 继承背景下,对象属性的查找顺序 派生 什么是派生 子类派生出新的属性,重用父类的属性 新式类和经典类 钻石继承的继承顺序 今日内容 一.组合 ...

随机推荐

  1. selenium PO模式

    思想: 1.定义basepage.py用来写公共方法,比如找元素,打开url,切换frame.这样的部分都写在这里.不必每次用都重写. 2.LoginPage.py 每个功能模块一个文件或者一个类 这 ...

  2. 31.JS实现控制HTML5背景音乐播放暂停

    实现控制网站背景音乐的播放暂停在html5中是非常容易和简单的,仅仅几行代码即可实现.首先在网页中嵌入背景音乐,html5代码为: <script src="http://wuover ...

  3. [11]Windows内核情景分析---设备驱动

    设备驱动 设备栈:从上层到下层的顺序依次是:过滤设备.类设备.过滤设备.小端口设备[过.类.过滤.小端口] 驱动栈:因设备堆栈原因而建立起来的一种堆栈 老式驱动:指不提供AddDevice的驱动,又叫 ...

  4. Robot framework selenium driver download

    Chrome: https://sites.google.com/a/chromium.org/chromedriver/downloads http://npm.taobao.org/mirrors ...

  5. Gardener Bo (树剖 + 问题分解)

    一开始没看懂计算答案的第四部和update2,很迷.然后一直推敲之后才发下我计算的时候漏掉一个关键点.没有把加值的影响放到父节点上. #include<bits/stdc++.h> #de ...

  6. chromedriver 全屏 翻页 错误

    from selenium import webdriver from selenium.common.exceptions import TimeoutException, StaleElement ...

  7. 设计模式之Strategy(策略)(转)

    Strategy是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个个封装成单独的类. Stratrgy应用比较广泛,比如, 公司经营业务变化图, 可能有两种实现方式,一个是线条曲 ...

  8. 禁用HTTP.sys,导致80端口被禁用和IIS服务无法启动解决办法

    由于端口被占用,使用 win+r 运行 cmd 输入netstat -ano 可以看到端口被PIF 4占用,可以找到对应的进程NT kernel& System 该进程是Http.sys,是h ...

  9. 75.Java异常处理机制-自定义异常

    package testDate; //自定义异常 public class MyException extends Exception{ public MyException(){ } public ...

  10. How to install john deere service advisor 4.2.005 on win 10 64bit

    How to install john deere service advisor 4.2.005 with the February 2016 data base disks on a machin ...