6

【Python】【面向对象】继承&多态

 2 years ago
source link: https://www.guofei.site/2017/10/07/inheritance.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

【Python】【面向对象】继承&多态

2017年10月07日

Author: Guofei

文章归类: 设计模式 ,文章编号: 1001


版权声明:本文作者是郭飞。转载随意,但需要标明原文链接,并通知本人
原文链接:https://www.guofei.site/2017/10/07/inheritance.html

Edit

继承

在继承时,
经典类是深度优先搜索
新式类是广度优先搜索(新式类继承自object)

经典类

class D():
    def bar(self):
        print('D.bar')

class C(D):
    def bar(self):
        print('C.bar')

class B(D):
    def bar1(self):
        print('B.bar')

class A(B, C):
    def bar(self):
        print('A.bar')

a = A()
# 经典类顶层不继承自任何对象
# 经典类执行方法时,采用深度优先搜索
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

新式类

class D(object):
    def bar(self):
        print('D.bar')

class C(D):
    def bar(self):
        print('C.bar')

class B(D):
    def bar1(self):
        print('B.bar')

class A(B, C):
    def bar(self):
        print('A.bar')

a = A()
# 新式类继承自object
# 新式类执行方法时,采用广度优先搜索
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

引用父类方法

子类继承父类时,会覆写父类的方法,有时候还想调用父类的方法(例如,使用 __init__ 方法时,想让父类的 __init__ 方法先运行一次),有两种方法解决:

  • 引用指定的父类方法
    import random
    import scipy.stats as stats
    class Fish:
      def __init__(self):
          self.position = stats.randint(1, 10).rvs(size=(2,))
      def move(self):
          self.position[0] -= 1
          print('move to {position}'.format(position=self.position))
    class Shark(Fish):
      def __init__(self):
          Fish.__init__(self) # 未绑定的父类方法
          self.ishungry = False
    shark = Shark()
    shark.move()
    shark.move()
    shark.move()
    
  • 使用super函数
    import random
    import scipy.stats as stats
    class Fish(object):
      def __init__(self,name='fish'):
          self.name=name
          self.position = stats.randint(1, 10).rvs(size=(2,))
      def move(self):
          self.position[0] -= 1
          print('move to {position}'.format(position=self.position))
    class Shark(Fish):
      def __init__(self):
          super().__init__(name='shark')  # super方法,好处是不用一一去找父类的名称,改继承关系很方便
          # Python2 是这么做的:super(B, self).__init__(x)
          self.ishungry = False
    shark = Shark()
    shark.move()
    shark.move()
    shark.move()
    

__new__ 方法">__new__ 方法

class A:
    def __new__(cls, *args, **kwargs):
        print(cls, args, kwargs)

    def __init__(self, value):
        self.value = value
        print(self)


a = A(1)
# 发现 __init__ 未被调用

__new__ 方法调用的 __init__

  • __new__ 是一个静态方法
  • __new__ 返回类的对象,然后自动用 __init__ 初始化。如果没有返回对象,那么 __init__ 不被调用
  • __init__ 不显示返回(或者只能return None),否则报错
  • __new____init__ 的入参必须一模一样,否则报错

多态

Pyhon不支持多态并且也用不到多态,或者说Python天然有多态性。多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

class F1:
    pass

class S1(F1):

    def show(self):
        print('S1.show')

class S2(F1):

    def show(self):
        print('S2.show')



def Func(obj):
    """Func函数需要接收一个F1类型或者F1子类的类型"""
    obj.show()
    #print()

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

由于在Java或C#中定义函数参数时,必须指定参数的类型
为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
而实际传入的参数是:S1对象和S2对象

元类

def hello(self):
    self.name = 10
    print("hello world")


Test = type('Test', (object,), {'num': 0,'hello':hello})
# 3个参数,类名,父类名。第三个字典中是类属性、类方式、静态方法
t = Test()

其它

self是什么

self 是类的实例

class Test:
    def prt(self):
        print(self)
        print(self.__class__)

t=Test()

print(t)
t.prt()

# 输出是:
# <__main__.Test object at 0x7fa25d134d30>
# <__main__.Test object at 0x7fa25d134d30>
# <class '__main__.Test'>

结论:self是类的实例

在继承时,self是什么

class Parent:
    def pprt(self):
        print(self)

class Child(Parent):
    def cprt(self):
        print(self)
c = Child()
c.cprt()
c.pprt()
p = Parent()
p.pprt()

# <__main__.Child object at 0x7fa25d1346a0>
# <__main__.Child object at 0x7fa25d1346a0>
# <__main__.Parent object at 0x7fa25d134668>

继承时,即使方法是在父类中定义的,self也是这次的实例(或者说,继承时从父类中把方法借过来给自己用)


您的支持将鼓励我继续创作!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK