面向对象之封装,多态
-
封装
-
定义:将内容封装在某个地方,以后再去调用被封装在某处的内容
-
第一步:将内容封装到某处
class A: def __init__(self,name,age): # 称为构造方法,根据类创建对象时自动执行 self.name = name self.age = age obj1 = A('铁憨憨',18) # 将铁憨憨和18分别封装到obj1及self的name和age属性中 obj2 = A('皮皮寒',16) # 将皮皮寒和16分别封装到obj1及self的name和age属性中
-
第二步:从某处调用被封装的内容
-
通过对象直接调用
class A: def __init__(self,name,age): self.name = name self.age = age obj1 = A('铁憨憨',18) obj2 = A('皮皮寒',16) print(obj1.name) print(obj2.age)
-
通过self间接调用
class A: def __init__(self,name,age): self.name = name self.age = age def func(self): print(self.name) obj1 = A('铁憨憨',18) obj2 = A('皮皮寒',16) obj1.func()
-
-
-
多态
-
定义:同一个对象多种形态,python默认支持多态
在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。
类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
-
鸭子类型
你看起来像鸭子,那么你就是鸭子。如下代码:
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两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。 # 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。 # 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。 # str bytes 等等 这就是互称为鸭子类型。
-
-
super
super是严格按照类的继承顺序执行的。
class A: def f1(self): print('in A') class Foo(A): def f1(self): super().f1() print('in Foo') class Bar(A): def f1(self): print('in Bar') class Info(Foo,Bar): def f1(self): super().f1() print('in Info f1') obj = Info() obj.f1() ''' in Bar in Foo in Info f1 ''' print(Info.mro()) # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
class A: def f1(self): print('in A') class Foo(A): def f1(self): super().f1() print('in Foo') class Bar(A): def f1(self): print('in Bar') class Info(Foo,Bar): def f1(self): super(Foo,self).f1() print('in Info f1') obj = Info() obj.f1() # in Bar # in Info f1
-
类的约束
在某些的情况下(在一些重要的逻辑,与用户数据相关等核心部分),我们要建立一种约束,避免发生此类错误.
-
在父类建立一种约束
提取父类,然后在父类中定义好方法,在这个⽅法中什么都不用干,就抛⼀个异常就可以了,这样所有的子类都必须重写这个方法,否则,访问的时候就会报错。
class Payment: """ 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。 """ def pay(self,money): raise Exception('子类必须定义此方法') class Alipay(Payment): def pay(self,money): print(f'利用支付宝支付了{money}') class QQpay(Payment): def pay(self,money): print(f'利用qq支付了{money}') class Wechatpay(Payment): def fuqian(self,money): print(f'利用微信支付了{money}') def pay(obj,money): obj.pay(money) obj3 = Wechatpay() pay(obj3,100) # 由于Wechatpay中没有pay方法,会执行Payment中的pay,会弹出错误
-
模拟抽象类(制定一种规范)的概念,建立一种概念
使用元类来描述父类,在元类中给出一个抽象方法,这样子类就不得不给出抽象方法的具体实现,也可以起到约束效果
from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): # # 抽象类 接口类 规范和约束 metaclass指定的是一个元类 @abstractmethod def pay(self,money): # 抽象方法 pass class Alipay(Payment): def pay(self,money): print(f'利用支付宝支付了{money}') class QQpay(Payment): def pay(self,money): print(f'利用qq支付了{money}') class Wechatpay(Payment): def fuqian(self,money): print(f'利用微信支付了{money}') def pay(obj,money): obj.pay(money) obj3 = Wechatpay() # 在实例化时@abstractmethod会判断obj3中有没有pay方法,如果没有就会报错 pay(obj3,100)
-
总结:约束就是父类对子类进行约束,子类必须要写xxx方法。
- 使用抽象类和抽象方法,由于改方案来源是java和c#,所以使用频率很少
- 使用认为抛出异常的方案,并且尽量抛出的是NotlmplementError,这样比较专业,而且错误比较明确。
-