Python 面向对象(其五)

类的多态继承

Python中,没有绝对的共有和私有,以及权限划分。所谓的共有、私有、内部变量都是通过约定是实现的。

  • def method() 约定为共有方法
  • def _method() 约定为私有方法,不期望外部使用,在代码中应该尽量避免使用内部变量和方法
  • def __method 为类方法,只属于当前类

某年月,忽然有个小小明要来找小明认亲了

    ---------------------------------------
                      小小明
    --------------------属性----------------
        父亲:超人小明
        母亲:阿花
    --------------------方法----------------
        来历:小明入魔后,阿花来唤醒他。然后。。。
        滚出去:毕竟是亲生的,这个设定也遗传了
        唤醒小明:继承自母亲的能力,以血缘唤回小明
  • 属性说明:
    • 小小明继承了 父亲:超人小明 和 母亲:阿花 两个人的基本属性
  • 方法说明:
    • 来历: 小明作为一个独立的人,能准确说出小明和阿花的爱恨情仇
    • 滚出去:毕竟是亲生的嘛
    • 唤醒小明:继承自母亲的能力
  • 补充说明:
    • 即便小小明是小明亲生的,小小明也不可能完全继承小明的所有能力,这些在代码中表现为私有属性/方法
    • 比如老婆、比如变身成超人、比如和阿花的关系。。。
 1 #! coding:utf-8
 2 class SuperManXiaoMing(object):
 3 
 4     def __init__(self):
 5         self.name = "小明"
 6         self.age = 40
 7         self._lovesOther = ["阿芳", "阿花"]
 8         self.__wife = "阿芳"
 9         self._favor = "对18-28年轻漂亮的女孩子特别专一"
10 
11     def goOut(self):
12         return "谁敢让本超人滚出去!"
13 
14     def __beSuperMan(self):
15         return "小明长大了,变成了一个好多妹子喜欢的超人小明"
16 
17     def _sayLoves(self):
18         for love in self._lovesOther:
19             print ("{}, 我是{}, 我爱你".format(love, self.name))
20 
21 class AHua(object):
22 
23     def __init__(self):
24         self.name = "阿花"
25         self.age = 35
26         self._money = "穷是我的色彩"
27 
28     def call_XiaoMing_back(self):
29         '''
30         太肉麻,写不出来,自己脑补吧
31         :return:
32         '''
33         return "小明,你还记得你说永远不会伤害我嘛"
34 
35 class XiaoXiaoMing(SuperManXiaoMing, AHua):
36 
37     def __init__(self, lovesOther):
38         SuperManXiaoMing.__init__(self)
39         AHua.__init__(self)
40         self.name = "小小明"
41         self.age = "10"
42         self._lovesOther = lovesOther
43 
44     def goOut(self):
45         return "我可是超人的儿子!好吧,我滚就是了"
46 
47     def call_XiaoMing_back(self):
48         return "阿爹,你站着别动,我去买点橘子"
49 
50     def where_Im_from_(self):
51         return "我爹叫{}, 我妈叫{},他们是在一个月黑风高的晚上。。。。".format(SuperManXiaoMing().name, AHua().name)
52 
53     def __beSuperMan(self):
54         return "我还没长大呢"
55 
56 if __name__ == '__main__':
57     xiao = XiaoXiaoMing(["小丽"])
58     print ("我叫{},今年{}。你们不要欺负我,因为{}".format(xiao.name, xiao.age, xiao.where_Im_from_()))
59     xiao._sayLoves()
60     print(xiao.call_XiaoMing_back())
61     print(xiao.goOut())
62 #----------------------------------output----------------------------
63 # 我叫小小明,今年10。你们不要欺负我,因为我爹叫小明, 我妈叫阿花,他们是在一个月黑风高的晚上。。。。
64 # 小丽, 我是小小明, 我爱你
65 # 阿爹,你站着别动,我去买点橘子
66 # 我可是超人的儿子!好吧,我滚就是了
67 
68     print(xiao._SuperManXiaoMing__beSuperMan())
69     print(xiao._XiaoXiaoMing__beSuperMan())
70 #----------------------------------output----------------------------
71 # 小明长大了,变成了一个好多妹子喜欢的超人小明
72 # 我还没长大呢

注意:

  • 在上述例子中,SuperManXiaoMing中的__beSuperMan只属于SuperManXiaoMing类,无法被子类继承
  • 所有的私有和共有属性都可以被继承

super 和 parentClass.__init__的区别

上述例子中,XiaoXiaoMing 的初始化,采用的是显示初始化

class XiaoXiaoMing(SuperManXiaoMing, AHua):

    def __init__(self, lovesOther):
        SuperManXiaoMing.__init__(self)
        AHua.__init__(self)

当然,也可以使用super做隐式初始化

class XiaoXiaoMing(SuperManXiaoMing, AHua):

    def __init__(self, lovesOther):
        super().__init__(self)

这两种的区别为:

显示调用会顺序执行所有父类的方法,在多继承的情况下,甚至会出现多次执行的父类初始化方法的情况,隐式调用就只会执行一次

示例代码如下:

ParentClass.__init__方式

#! coding:utf-8
class Man(object):
    def __init__(self):
        print("Man.__init__")

class BaBa(Man):

    def __init__(self):
        Man.__init__(self)
        print("BaBa.__init__")

class MaMa(Man):
    def __init__(self):
        Man.__init__(self)
        print ("MaMa.__init__")

class You(BaBa,MaMa):
    def __init__(self):
        BaBa.__init__(self)
        MaMa.__init__(self)
        print("You.__init__")
you = You()

# ----------------------------------output----------------------------
# Man.__init__
# BaBa.__init__
# Man.__init__
# MaMa.__init__
# You.__init__

可以看出,Man.__init__被调用了两次

Super().__init__方式

class Man(object):
    def __init__(self):
        print("Man.__init__")

class BaBa(Man):

    def __init__(self):
        super().__init__()
        print("BaBa.__init__")

class MaMa(Man):
    def __init__(self):
        super().__init__()
        print ("MaMa.__init__")

class You(BaBa,MaMa):
    def __init__(self):
        super().__init__()
        print("You.__init__")
you = You()

# ----------------------------------output----------------------------
# Man.__init__
# MaMa.__init__
# BaBa.__init__
# You.__init__

Man.__init__只调用了一次

多继承中初始化参数的问题

上述例子中,Super的情况仅适用于 两个父对象的初始化方法参数相同,如果参数不同的话要怎样做呢?

一种做法是如之前例子中显式的初始化每一个父类,并单独赋值

class XiaoXiaoMing(SuperManXiaoMing, AHua):
    def __init__(self, lovesOther, husband):
        SuperManXiaoMing.__init__(self, lovesOther)
        AHua.__init__(self,husband)

另一种做法是使用Super进行单独赋值

class XiaoXiaoMing(SuperManXiaoMing, AHua):
    def __init__(self, lovesOther, husband):
        super().__init__(lovesOther)
        super(SuperManXiaoMing, self).__init__(husband)

这种写法不会减少父类的重复调用

super方法在初始化时遵循MRO算法,

在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变

如上述例子中,super的执行顺序就是

XiaoXiaoMing --> SuperManXiaoMing --> Ahua
                      |
                      |-----> XiaoMing

super().__init__()默认参数为当前类,指的是第二个类SuperManXiaoMing,等价于 super(XiaoXiaoMing,self).__init__()
如果赋值为SuperManXiaoMing, super(SuperManXiaoMing, self).__init__()就指的是 Ahua

使用如下方式进行查看

class XiaoXiaoMing(SuperManXiaoMing, AHua):
    def __init__(self, lovesOther, husband):
        print(super())
        super().__init__(lovesOther)
        super(SuperManXiaoMing, self).__init__(husband)
原文地址:https://www.cnblogs.com/SilenceCity/p/pythonOO5.html