一、类的继承顺序
只要继承object类就是新式类
不继承object类的都是经典类
在python3 中所有的类都继承object类,都是新式类
在python2 中不继承object的类都是经典类
继承object类的就是新式类
经典类:在py3中不存在,在py2中不主动继承object类
父类对子类的约束
抽象类:是一个开发的规范,约束它的所有子类必须实现一些和它同名的方法
列如:支付程序。
-
微信支付 URL链接,告诉你参数什么格式
-
{ ' username ' : ' 用户名 ' , ' money ' : 200 }
-
-
支付宝支付 URL链接,告诉你参数什么格式
-
{ ' uname ' : ' 用户名 ' , ' price' : 200 }
-
方法一:
class Payment: # 这是个抽象类 def pay(self, money): ''' 只要你见到了项目中有这种类,你要知道你的子类中必须实现和pay同名的方法 ''' raise NotImplementedError('请在类中重写重名pay类方法') # 主动抛异常 class WeChat(Payment): def __init__(self, username): self.username = username def pay(self, money): # pay方法名字不能改变 dic = {'username': self.username, 'money': money} ''' 调用微信支付 url连接 把dic传过去 ''' print(f'{self.username}通过微信充值了{money}') class Alipay(Payment): def __init__(self, username): self.username = username def pay1(self, money): dic = {'uname': self.username, 'price': money} '''' 调用支付宝支付 url连接 把dic传过去 ''' print(f'{self.username}通过支付宝充值了{money}') # 归一化设计:同事或用户使用此类时,直接调用pay函数传参,不用自己创建对象 def pay(username, money, kind): if kind == 'WeChat': obj = WeChat(username) elif kind == 'Alipay': obj = Alipay(username) obj.pay(money) pay('小杨', 200, 'WeChat') # 当支付宝的pay方法名字发生改变时 pay('小杨', 200, 'Alipay') # 输出 小杨通过微信充值了200 报错:NotImplementedError: 请在类中重写重名pay类方法
方法二:实现抽象类的另一种方式,约束力强,依赖abc模块
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 这是个抽象类 @abstractmethod def pay(self, money): pass class WeChat(Payment): def __init__(self, username): self.username = username def pay(self, money): # pay方法名字不能改变 dic = {'username': self.username, 'money': money} ''' 调用微信支付 url连接 把dic传过去 ''' print(f'{self.username}通过微信充值了{money}') class Alipay(Payment): def __init__(self, username): self.username = username def pay1(self, money): dic = {'uname': self.username, 'price': money} '''' 调用支付宝支付 url连接 把dic传过去 ''' print(f'{self.username}通过支付宝充值了{money}') # 当支付宝的pay名字发生变化的时候 Alipay('xiao') # 这种方法在实例化对象的时候就会报错提示 # 输出 TypeError: Can't instantiate abstract class Alipay with abstract method pay
三、多态
一个类型表现出来的多种状态:
-
同一个对象,多种形态。python默认支持多态
def func(count): # 这里的count可以是str、int、list、dict等等....count就是多态的 print(count) func('abc') func(12345) func([1, 2, 3, 4]) func({'a': 1, 'b': 2}) # 输出 abc 12345 [1, 2, 3, 4] {'a': 1, 'b': 2}
而在Java的情况下:
-
一个参数必须指定类型
-
所以如果想两个类型的对象都可以传,那么必须让着两个继承自一个父类,在指定类型的时候使用父类来指定
-
在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。
def func(int a): print('a必须是数学')
-
而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
def func(a): print('a是什么都可以')
python伪代码实现Java或C的多态
class F1: pass class S1(F1): def show(self): print 'S1.show' class S2(F1): def show(self): print 'S2.show' # 由于在Java或C#中定义函数参数时,必须指定参数的类型 # 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类 # 而实际传入的参数是:S1对象和S2对象 def Func(F1 obj): """Func函数需要接收一个F1类型或者F1子类的类型""" print obj.show() s1_obj = S1() Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show s2_obj = S2() Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
鸭子类型
在python中,有一句谚语,你看起来像鸭子,那么你就是鸭子。
对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
比如:str、tuple、list 都有index方法,这就是互称为鸭子类型
class A: def f1(self): print('in A f1') def f2(self): print('in A f2') class B: def f1(self): print('in A f1') def f2(self): print('in A f2') obj = A() obj.f1() obj.f2() obj2 = B() obj2.f1() obj2.f2() # A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。 # 输出 in A f1 in A f2 in A f1 in A f2