python 面向对象的三大特性:继承,封装,多态。

  1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜ B 的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.
  2. 继承: ⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在 python 中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号, 就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了 x 是⼀种 y. 这时, y 是⼀种泛化的概念. x 比 y 更加具体. 那这时 x 就是 y 的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的 “ 动 “ 这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫 “ 吃⼈ “, ⽩骨精⼀出⽣就知道如何 “ 吃⼈ “. 此时 ⽩骨精继承妖精.
  3. 多态: 同⼀个对象, 多种形态. 这个在 python 中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量 a = 10 , 我们知道此时 a 是整数类型. 但是我们可以通过程序让 a = “hello”, 这时, a ⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量 a 可以是多种形态。

封装

第一步:将内容封装到某处

  1. class Foo:
  2. def __init__(self,name,age):
  3. self.name = name
  4. self.age = age
  5. obj1 = Foo('chensong',18)
  6. obj2 = Foo('aaron',16)

Python
Copy
第二步:从某处调用被封装的内容

  1. class Foo:
  2. def __init__(self,name,age):
  3. self.name = name
  4. self.age = age
  5. def detail(self):
  6. print(self.name)
  7. print(self.age)
  8. obj1 = Foo('chensong',18)
  9. obj2 = Foo('aaron',16)
  10. print(obj1.name)
  11. print(obj2.age)
  12. # 通过对象直接调用被封装的内容
  13. obj1.detail()
  14. obj2.detail()
  15. # 通过self间接调用被封装的内容

Python
Copy

多态

多态,同一个对象,多种形态。python 默认支持多态。
python 中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
对于代码上的解释其实很简答:

  1. class A:
  2. def f1(self):
  3. print('in A f1')
  4. def f2(self):
  5. print('in A f2')
  6. class B:
  7. def f1(self):
  8. print('in B f1')
  9. def f2(self):
  10. print('in B f2')
  11. obj = A()
  12. obj.f1()
  13. obj.f2()
  14. obj2 = B()
  15. obj2.f1()
  16. obj2.f2()
  17. # A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
  18. # 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
  19. # 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。
  20. # str bytes 等等 这就是互称为鸭子类型。

Python
Copy

类的约束

写一个支付功能

  1. class QQpay:
  2. def pay(self,money):
  3. print('使用qq支付%s元' % money)
  4. class Alipay:
  5. def pay(self,money):
  6. print('使用阿里支付%s元' % money)
  7. a = Alipay()
  8. a.pay(100)
  9. b = QQpay()
  10. b.pay(200)

Python
Copy
统一一下付款方式

  1. class QQpay:
  2. def pay(self,money):
  3. print('使用qq支付%s元' % money)
  4. class Alipay:
  5. def pay(self,money):
  6. print('使用阿里支付%s元' % money)
  7. def pay(obj,money):
  8. obj.pay(money)
  9. a = Alipay()
  10. b = QQpay()
  11. pay(a,100)
  12. pay(b,200)

Python
Copy
如果后期添加微信支付,但是没有统一标准,换个程序员就可能写成这样

  1. class QQpay:
  2. def pay(self,money):
  3. print('使用qq支付%s元' % money)
  4. class Alipay:
  5. def pay(self,money):
  6. print('使用阿里支付%s元' % money)
  7. class Wechatpay:
  8. def fuqian(self,money):
  9. print('使用微信支付%s元' % money)
  10. def pay(obj,money):
  11. obj.pay(money)
  12. a = Alipay()
  13. b = QQpay()
  14. pay(a,100)
  15. pay(b,200)
  16. c = Wechatpay()
  17. c.fuqian(300)

Python
Copy
所以此时我们要用到对类的约束,对类的约束有两种:

  1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
  2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.
  • 先用第一种方法解决问题

    1. class Payment:
    2. """
    3. 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。
    4. """
    5. def pay(self,money):
    6. raise Exception("你没有实现pay方法")
    7. class QQpay(Payment):
    8. def pay(self,money):
    9. print('使用qq支付%s元' % money)
    10. class Alipay(Payment):
    11. def pay(self,money):
    12. print('使用阿里支付%s元' % money)
    13. class Wechatpay(Payment):
    14. def fuqian(self,money):
    15. print('使用微信支付%s元' % money)
    16. def pay(obj,money):
    17. obj.pay(money)
    18. a = Alipay()
    19. b = QQpay()
    20. c = Wechatpay()
    21. pay(a,100)
    22. pay(b,200)
    23. pay(c,300)

    Python
    Copy

  • 引入抽象类的概念处理

    1. from abc import ABCMeta,abstractmethod
    2. class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类
    3. @abstractmethod
    4. def pay(self):pass # 抽象方法
    5. class Alipay(Payment):
    6. def pay(self,money):
    7. print('使用支付宝支付了%s元'%money)
    8. class QQpay(Payment):
    9. def pay(self,money):
    10. print('使用qq支付了%s元'%money)
    11. class Wechatpay(Payment):
    12. # def pay(self,money):
    13. # print('使用微信支付了%s元'%money)
    14. def recharge(self):pass
    15. def pay(a,money):
    16. a.pay(money)
    17. a = Alipay()
    18. a.pay(100)
    19. pay(a,100) # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
    20. q = QQpay()
    21. q.pay(100)
    22. pay(q,100)
    23. w = Wechatpay()
    24. pay(w,100) # 到用的时候才会报错
    25. # 抽象类和接口类做的事情 :建立规范
    26. # 制定一个类的metaclass是ABCMeta,
    27. # 那么这个类就变成了一个抽象类(接口类)
    28. # 这个类的主要功能就是建立一个规范

    Python
    Copy
    总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写 xxx ⽅法. 在 python 中约束的⽅式和⽅法有两种:

  1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是 java 和 c#. 所以使⽤频率还是很少的
  2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是 NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐)

super() 深入了解

super 是严格按照类的继承顺序执行!!!

  1. class A:
  2. def f1(self):
  3. print('in A f1')
  4. def f2(self):
  5. print('in A f2')
  6. class Foo(A):
  7. def f1(self):
  8. super().f2()
  9. print('in A Foo')
  10. obj = Foo()
  11. obj.f1()

Python
Copy

  1. class A:
  2. def f1(self):
  3. print('in A')
  4. class Foo(A):
  5. def f1(self):
  6. super().f1()
  7. print('in Foo')
  8. class Bar(A):
  9. def f1(self):
  10. print('in Bar')
  11. class Info(Foo,Bar):
  12. def f1(self):
  13. super().f1()
  14. print('in Info f1')
  15. obj = Info()
  16. obj.f1()
  17. print(Info.mro())

Python
Copy

  1. class A:
  2. def f1(self):
  3. print('in A')
  4. class Foo(A):
  5. def f1(self):
  6. super().f1()
  7. print('in Foo')
  8. class Bar(A):
  9. def f1(self):
  10. print('in Bar')
  11. class Info(Foo,Bar):
  12. def f1(self):
  13. super(Foo,self).f1()
  14. print('in Info f1')
  15. obj = Info()
  16. obj.f1()