面向对象三大特性之继承,封装,多态
继承:
专业角度: B 继承 A类, B就叫做A的子类,派生类, A叫做B的父类,基类,超类. B类以及B类的对象使用A类的所有的属性以及方法.
字面意思: 继承就是继承父母所有的资产.
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
class Aniaml(object): def __init__(self,name,sex,age): self.name = name self.age = age self.sex = sex class Person(Aniaml): # 因为Person,Cat,Dog有相同的属性name,sex,age pass # 所以将相同的部分单独拿出来,新建一个类,让这三个类 # 继承这个类 class Cat(Aniaml): pass class Dog(Aniaml): pass
继承的优点:
1.减少了重复代码,
2.增加了类与类之间的耦合性(继承宜精,不宜多)
3.是代码更加规范化,合理化
继承的缺点:
过度的继承,类与类之间的耦合性太强,可读性差,修改的时候牵一发而动全身。
Aminal 叫做父类,基类,超类。 Person Cat Dog: 子类,派生类。 继承:可以分单继承,多继承。
这里需要补充一下python中类的种类(继承需要):
继承的分类:
python2.2之前:都是经典类,
python2.2直至python2.7之间存在两种类型: 经典类,新式类.
经典类: 基类不继承object,查询规则 依靠:深度优先的原则.
新式类: 基类必须继承object,查询规则: mro算法.
python3x 只有新式类.
单继承
1.子类以及对象可以调用父类中的方法和属性
class Animal(object): live='有生命的' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def eat(self): print(self) # self==对象p1 print('动物都需要进食') class Person(Animal): pass 1.从类名执行父类的属性 print(Person.__dict__) print(Person.live) Person.eat(55) 2.从对象执行父类属性 实例化对象一定会执行三件事,一定会__init__ p1=Person('dsb',21,'laddy_boy') # print(p1.__dict__) print(p1.live) p1.eat() print(p1)
注意:子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改)
2.执行顺序:
# 执行顺序 class Animal(object): type_name = '动物类' def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age def eat(self): print(self) print('吃东西') class Person(Animal): def eat(self): print(f'{self.name}吃饭') class Cat(Animal): pass class Dog(Animal): pass p1 = Person('太上老君', '男', 18) # 实例化对象时必须执行__init__方法,类中没有,父类没有,从object类中找 p1.eat() # 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法
多继承
经典类的多继承
新式类的多继承
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] ) mro(Foo(H,G)) = [Foo] + merge(mro(H), mro(G),[H,G]) 表头: 列表的第一个元素 表尾: 列表中表头以外的元素集合(可以为空) 表头,表尾 [A,B,C] : 表头: A 表尾: [B,C] [A] : 表头: A 表尾: [] mro(A) = mro(A(B,C)) = [A] + merge(mro(B), mro(C), [B,C]) mro(B) = mro(B(D,E)) = [B] + merge(mro(D), mro(E), [D,E]) = [B] + merge([D,O], [E,O], [D,E]) = [B,D] + merge([O], [E,O], [E]) = [B,D,E,O] mro(C) = mro(C(E,F)) = [C] + merge(mro(E), mro(F),[E,F]) = [C] + merge([E,O],[F,O],[E,F]) = [C,E] + merge([O],[F,O],[F]) = [C,E,F,O] mro(A) = mro(A(B,C)) = [A] + merge([B,D,E,O], [C,E,F,O], [B,C]) = [A,B] + merge([D,E,O], [C,E,F,O], [C]) = [A,B,D] + merge([E,O], [C,E,F,O], [C]) = [A,B,D,C] + merge([E,O], [E,F,O]) = [A,B,D,C,E] + merge([O], [F,O]) = [A,B,D,C,E,F,O]
super()的用法:
既可以执行父类的方法又可以执行子类中的方法
class Animal(object): live = '有生命的' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def eat(self): print('动物都需要进食') class Person(Animal): def __init__(self, name, age, sex,habby): # super(Person, self).__init__(name,age,sex) super().__init__(name,age,sex) self.habby=habby def eat(self): print('人类需要进食') super().eat() # super()继承父类中的方法,可以调用父类中的方法 p1=Person('怼怼哥',23,'不详','吹牛逼') print(p1.__dict__) p1.eat()
封装
封装: 将一些东西内容封装到一个地方,用的时候还可以在取出来.
类设置静态属性, 设置一些方法,
对象.对象可以在其对象空间中封装一些属性.
# 封装: 顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容 # 第一步: 将内容封装到某个地方 class Foo: def __init__(self, name, age): self.name = name self.age = age def detail(self): print(self.name) print(self.age) obj1 = Foo('小红', 18) obj2 = Foo('小花', 18) # 内容被封装到了对象obj1和obj2中,每个对象中都有name和age属性 --------------------------------------------------------- # 第二步: 从某处调用被封装的内容 # 通过对象直接调用 print(obj1.name) print(obj2.name) # 通过self间接调用被封装的内容 obj1.detail()
多态
定义:一种事务有多种形态 水: 气态液态固态.
比如定义一个变量,既可以是字符串,列表,字典,结合等,这个变量有多种形态
python默认支持多态
python中定义变量不用规定变量的类型
鸭子类型
A,B两个类没有任何的关系,相互独立,但是里面的功能相似, 所以python会将类似于A,B 两个类里面相似的功能让其命名相同
class A: def login(self): pass def register(self): pass class B: def login(self): pass def register(self): pass
A,B虽然无关系,但是很默契的制定了一个规范,让你使用起来更方便
class Str: def index(): pass def count(): pass class List: def index(): pass def count(): pass
类的约束
对类的约束有两种:
1.提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 执行的时候就会报错.
2.使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.
class QQpay: def pay(self,money): print(f'利用QQ支付了{money}') class Alipay: def pay(self,money): print(f'利用支付宝支付了{money}') class Wechatpay: # def weixin(self,money): # print(f'利用微信支付了{money}') def pay(self,money): print(f'利用微信支付了{money}') def pay(obj,money): # 归一化设计 obj.pay(money) obj1=QQpay() pay(obj1,300) obj2=Alipay() pay(obj2,300) # obj3=Wechatpay() # obj3.weixin(300) #虽然实现了调用,但是调用的方式不统一 obj3=Wechatpay() obj3.pay(300)
也可以将以上三个函数方法到函数的内部,
def pay(): choices=input('请选择你支付的方式:QQ,Alipay,Wechatpay') # 在此通过判断,将三个实例化放入函数的内部
pay() 在上面的情况在(在一些重要的逻辑,与用户数据性相关的的核心部分),我们要建立一种约束,避免此类的发生。 类的约束有两种解决方式: 1.在父类建立一种约束。 2.模拟抽象类(指定一种规范)的概念,建立一种约束。
第一种解决方案: 第一种约束:在父类定义一个pay方法,主动抛异常,如果过子类中没有此方法,则会继承父类中的此方法, python推荐的一种约束方法。
class Payment: def pay(self,money): raise Exception('子类必须定义次方法') class QQpay(Payment): def pay(self,money): print(f'利用QQ支付了{money}') class Alipay(Payment): def pay(self,money): print(f'利用支付宝支付了{money}') class Wechatpay(Payment): def weixin(self,money): print(f'利用微信支付了{money}') def pay(obj,money): obj.pay(money) obj3=Wechatpay() pay(obj3,300)
第二种解决方案: 利用抽象类的概念:基类加上设置,设置一个方法,子类如果没有定义这个方法,则在实例化的时候就会报错
from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): @abstractmethod def pay(self,money): pass class QQpay(Payment): def pay(self,money): print(f'利用QQ支付了{money}') class Alipay(Payment): def pay(self,money): print(f'利用支付宝支付了{money}') class Wechatpay(Payment): def weixin(self,money): print(f'利用微信支付了{money}') obj3=Wechatpay()
深入了解super
单继承:supper()肯定是执行父类的方法
多继承:supper(S,self)严格按照self从属于类的mro的执行顺序,执行S类的下一位,类
class A: def f1(self): print('in A') class Foo(A): def f1(self): super(Foo,self).f1() print('in Foo') class Bar(A): def f1(self): print('in Bar') class Info(Foo,Bar): def f1(self): super(Info,self).f1() print('in Info f1') obj=Info() Info的mro的执行顺序:Info ,Foo,Bar,A obj.f1()
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() # 所以此处应该找Bar类中的f1 print('in Info f1') obj=Info() # Info的mro的执行顺序:Info ,Foo,Bar,A obj.f1() Info().f1()

浙公网安备 33010602011771号