面向对象三大特性之继承,封装,多态

三大特性:

  继承:

    专业角度: 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):
    passclass Dog(Aniaml):
    pass
View Code

 

  继承的优点:

    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)
View Code

    注意:子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改)

    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方法,自己类没有才能执行父类中的方法
View Code
  多继承
    经典类的多继承

 

    新式类的多继承

     
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]
​
mro算法
    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()
View Code

  封装

    封装: 将一些东西内容封装到一个地方,用的时候还可以在取出来.

    类设置静态属性, 设置一些方法,

    对象.对象可以在其对象空间中封装一些属性.

    
# 封装: 顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容
# 第一步: 将内容封装到某个地方
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()
View Code

  多态

    定义:一种事务有多种形态 水: 气态液态固态.

    比如定义一个变量,既可以是字符串,列表,字典,结合等,这个变量有多种形态

    python默认支持多态

    python中定义变量不用规定变量的类型

  鸭子类型

    A,B两个类没有任何的关系,相互独立,但是里面的功能相似, 所以python会将类似于A,B 两个类里面相似的功能让其命名相同

    
class A:
    def login(self):
        passdef register(self):
        pass
​
​
class B:
    def login(self):
        passdef register(self):
        pass
View Code

    A,B虽然无关系,但是很默契的制定了一个规范,让你使用起来更方便

    
class Str:
    def index():
        pass 
    def count():
        pass
        
        
class List:
    def index():
        pass
    def count():
        pass
View Code

  类的约束

    对类的约束有两种:

      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)
View Code

    也可以将以上三个函数方法到函数的内部,

    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)
View Code

    第二种解决方案: 利用抽象类的概念:基类加上设置,设置一个方法,子类如果没有定义这个方法,则在实例化的时候就会报错

    
from abc import ABCMeta,abstractmethod
​
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        passclass 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()
View Code

  深入了解super

    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()
​
例二:
posted @ 2019-07-20 11:01  奋斗的小文6  Views(141)  Comments(0)    收藏  举报