python判断对象继承关系的是_python基础(面向对象(超(父)类、子类继承)、继承判断、MRO方法解析顺序)...

为啥要继承

0b83e043134c5dc02160b6e662b5ea60.png

说明

能够提升代码的重用率,即开发一个类,可以在多个子功能中直接使用

继承能够有效的进行代码的管理,当某个类有问题只要修改这个类就行,而其继承这个类的子类往往不需要就修改

继承

程序员总是想避免多次输入同样的代码。这通过创建函数来达成这个目标,但现在要解决一个更微妙的问题。如果你已经有了一个类,并要创建一个与之很像的类(可能只是新增了几个方法),该如何办呢?创建这个新类时,你不想复制旧类的代码,将其粘贴到新类中。

例如,你可能已经有了一个名为Shape的类,它知道如何将自己绘制到屏幕上。现在你想创建一个名为Rectangle的类,但它不仅知道如何将自己绘制到屏幕上,而且还知道如何计算其面积。你不想重新编写方法draw,因为Shape已经有一个这样的方法,且效果很好。那么该如何办呢?让Rectangle继承Shape的方法,使得对Rectangle对象调用方法draw时,将自动调用Shape类的这个方法。

我们说的子类扩展了超类的定义。要指定超类,可在class语句中的类名后加上超类名,并将其用圆括号括起。

class Filter:

def init(self):

self.blocked = []

def filter(self, sequence):

return [x for x in sequence if x not in self.blocked]

class SPAMFilter(Filter): # SPAMFilter是Filter的子类

def init(self): # 重写超类Filter的方法init

self.blocked = ['SPAM']

Filter是一个过滤序列的通用类。实际上,它不会过滤掉任何东西。

>>> f = Filter()

>>> f.init()

>>> f.filter([1, 2, 3])

[1, 2, 3]

Filter类的用途在于可用作其他类(如将'SPAM'从序列中过滤掉的SPAMFilter类)的基类(超类)。

>>> s = SPAMFilter()

>>> s.init()

>>> s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'eggs', 'bacon', 'SPAM'])

['eggs', 'bacon']

请注意SPAMFilter类的定义中有两个要点。

以提供新定义的方式重写了Filter类中方法init的定义。

直接从Filter类继承了方法filter的定义,因此无需重新编写其定义。

第二点说明了继承很有用的原因:可以创建大量不同的过滤器类,它们都从Filter类派生而来,并且都使用已编写好的方法filter。

继承判断

要确定一个类是否是另一个类的子类,可使用内置方法issubclass。

>>> issubclass(SPAMFilter, Filter)

True

>>> issubclass(Filter, SPAMFilter)

False

如果你有一个类,并想知道它的基类,可访问其特殊属性__bases__。

>>> SPAMFilter.__bases__

(,)

>>> Filter.__bases__

(,)

同样,要确定对象是否是特定类的实例,可使用isinstance。

>>> s = SPAMFilter()

>>> isinstance(s, SPAMFilter)

True

>>> isinstance(s, Filter)

True

>>> isinstance(s, str)

False

使用isinstance通常不是良好的做法,依赖多态在任何情况下都是更好的选择。一个重要的例外情况是使用抽象基类和模块abc时

如你所见,s是SPAMFilter类的(直接)实例,但它也是Filter类的间接实例,因为SPAMFilter是Filter的子类。换而言之,所有SPAMFilter对象都是Filter对象。从前一个示例可知,isinstance也可用于类型,如字符串类型(str)。

如果你要获悉对象属于哪个类,可使用属性__class__。

>>> s.__class__

对于新式类(无论是通过使用__metaclass__ = type还是通过从object继承创建的)的实例,还可使用type(s)来获悉其所属的类。对于所有旧式类的实例,type都只是返回instance。

继承多个超(父)类

前面,你肯定注意到了一个有点奇怪的细节:复数形式的__bases__。前面说过,你可使用它来获悉类的基类,而基类可能有多个。为说明如何继承多个类,下面来创建几个类。

class Calculator:

def calculate(self, expression):

self.value = eval(expression)

class Talker:

def talk(self):

print('Hi, my value is', self.value)

class TalkingCalculator(Calculator, Talker):

pass

子类TalkingCalculator本身无所作为,其所有的行为都是从超类那里继承的。关键是通过从Calculator那里继承calculate,并从Talker那里继承talk,它成了会说话的计算器。

>>> tc = TalkingCalculator()

>>> tc.calculate('1 + 2 * 3')

>>> tc.talk()

Hi, my value is 7

这被称为多重继承,是一个功能强大的工具。然而,除非万不得已,否则应避免使用多重继承,因为在有些情况下,它可能带来意外的“并发症”。使用多重继承时,有一点务必注意:如果多个超类以不同的方式实现了同一个方法(即有多个同名方法),必须在class语句中小心排列这些超类,因为位于前面的类的方法将覆盖位于后面的类的方法。因此,在前面的示例中,如果Calculator类包含方法talk,那么这个方法将覆盖Talker类的方法talk(导致它不可访问)。如果像下面这样反转超类的排列顺序:

class TalkingCalculator(Talker, Calculator): pass

将导致Talker的方法talk是可以访问的。多个超类的超类相同时,查找特定方法或属性时访问超类的顺序称为方法解析顺序(MRO),它使用的算法非常复杂。所幸其效果很好,可能根本无需担心。

MRO方法搜索顺序(方法解析顺序)

python中针对类提供了一个内置属性__mro__可以查看方法搜索顺序

MRO是method resolution order,主要用于多继承时判断方法、属性的调用路径

print(C.__mro__)   #输出结果,,

在搜索方法时,是按照__mro__的输出结果从左到右的顺序查找的

如果在当前类中找到方法,就直接执行,不再搜索

如果没有找到,就查找下个类中是否有对应的方法,如果找到,就直接执行,不再搜索

如果找到最后一个类,还没有找到方法,程序报错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值