当看到一只鸟走起来像鸭子、游泳像鸭子、叫起来也像鸭子,那么这只鸟就能够被称为鸭子python
判断某一个对象是否有某一个属性,hasattr()程序员
class Company(object): def __init__(self, employee_list): self.employee = employee_list def __getitem__(self, item): return self.employee[item] def __len__(self): return len(self.employee) print(hasattr(Company, "__len__")) company = Company(['tom', 'bob', 'jane']) print(hasattr(company, "__len__"))
判断某一个对象是不是某种类型,isinstance()web
对于判断对象是否能够调用某函数,更好的方法是去判断其是不是某种类型,而不是该对象是否有某个属性。redis
# 在某些状况下但愿断定某个对象的类型,咱们须要强制某个子类必须实现某些方法 from collections.abc import Sized class Company(object): def __init__(self, employee_list): self.employee = employee_list def __getitem__(self, item): return self.employee[item] def __len__(self): return len(self.employee) company = Company(['tom', 'bob', 'jane']) print(isinstance(company, Sized))
# 设计一个抽象基类,指定子类必须事项某些方法 # 实现一个web框架,集成cache(redis, cache, memorychache) class CacheBase(): def get(self, key): raise NotImplementedError def set(self, key, value): raise NotImplemnetedError class RedisCache(CacheBase): pass redis_cache = RedisCache() redis_cache.set("key", "value")
报错以下示:算法
# 做以下更改 class RedisCache(CacheBase): def __init__(self): self.dic = {} def get(self, key): return self.dic[key] if key in self.dic else None def set(self, key, value): self.dic[key] = value redis_cache = RedisCache() redis_cache.set("key", "value") print(redis_cache.get("key"))
class A(object): pass class B(A): pass class C(B): pass c = C() print(type(c)) # <class '__main__.C'> print(type(C)) # <class 'type'> print(isinstance(C, B)) # False print(isinstance(C, object)) # True
先实例属性再类属性编程
若是把实例当作是类,那么类变量就是父类中的属性,而实例变量是子类的属性,子类中没有父类有 会从父类中继承,子类中有父类有 至关于覆盖重写
框架
class A: name = 'bb' def __init__(self, x): self.x = x a1 = A(1) a2 = A(2) print(a1.name) #继承类变量bb print(a1.x) # 就是实例变量x的值 print(A.name) # 类变量bb A.name = 'dd' # 更改了类变量 print(A.name) # 类变量发生更改dd print(a1.name) # 实例的类变量也更改dd a1.name = 'name' print(a1.name) # 在此更改类变量 print(A.name) # 删除了实例属性 A.name = 'last' # 在此更改了类变量 del a1.name # 删除了实例变量 print(a1.name) # 继承类变量last
类变量和属性的调用顺序:函数
在python中,为了重用代码,能够使用在子类中使用父类的方法,可是在多继承中可能会出现重复调用的问题,支持多继承的面向对象编程均可能会致使钻石继承(菱形继承)问题 ,以下示:测试
class A(): def __init__(self): print("进入A…") print("离开A…") class B(A): def __init__(self): print("进入B…") A.__init__(self) print("离开B…") class C(A): def __init__(self): print("进入C…") A.__init__(self) print("离开C…") class D(B, C): def __init__(self): print("进入D…") B.__init__(self) C.__init__(self) print("离开D…") d = D() # 实际上会先找B, 而后找A, 而后是C, 再找A ''' 进入D… 进入B… 进入A… 离开A… 离开B… 进入C… 进入A… 离开A… 离开C… 离开D… '''
钻石继承(菱形继承)会带来什么问题?.net
多重继承容易致使钻石继承(菱形继承)问题,上边代码实例化 D 类后咱们发现 A 先后进入了两次。另外,假设 A 的初始化方法里有一个计数器,那这样 D 一实例化,A 的计数器就跑两次(若是遭遇多个钻石结构重叠还要更多),很明显是不符合程序设计的初衷的(程序应该可控,而不能受到继承关系影响)。
如何避免钻石继承(菱形继承)问题?
为解决这个问题,Python 使用了一个叫“方法解析顺序(Method Resolution Order,MRO)”的东西,还用了一个叫 C3 的算法。
MRO 的顺序基本就是:在避免同一类被调用屡次的前提下,使用广度优先和从左到右的原则去寻找须要的属性和方法。有则调用,没有就查找添加到MRO中。
在继承体系中,C3 算法确保同一个类只会被搜寻一次。例子中,若是一个属性或方法在 D 类中没有被找到,Python 就会搜寻 B 类,而后搜索 C类,若是都没有找到,会继续搜索 B 的基类 A,若是仍是没有找到,则抛出“AttributeError”异常。
能够使用 类名.mro 得到 MRO 的顺序(注:object 是全部类的基类,金字塔的顶端):
print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
为了防止多继承中的一些问题,使用C3算法解决,它可以保证调用链
中全部的类仅出现一次,也就是说每一个节点后面的类都不继承它,不然将它从调用链中删除,D.mro()
查看调用链。
而super()
的使用就是基于这条调用链,当使用super()时,会查找调用链,找到当前类,调用下一个类,没有则找下一个。super()默认是当前类,也能够写类名
class A(): def __init__(self): print("进入A…") print("离开A…") class B(A): def __init__(self): print("进入B…") super().__init__() print("离开B…") class C(A): def __init__(self): print("进入C…") super().__init__() print("离开C…") class D(B, C): def __init__(self): print("进入D…") super().__init__() print("离开D…") d = D() ''' 进入D… 进入B… 进入C… 进入A… 离开A… 离开C… 离开B… 离开D… '''
MRO的局限性:类型冲突时, 子类改变了基类的方法搜索顺序。而 子类不能改变基类的方法搜索顺序。在 Python 2.2 的 MRO 算法中并不能保证这种单调性,它不会阻止程序员写出上述具备二义性的继承关系,所以极可能成为错误的根源。
博客:https://mp.weixin.qq.com/s?src=11×tamp=1606794886&ver=2739&signature=SRS5nobqUFoRtzuAsoe8pOknkOYeNxLZz90OnfG3sQtaaMcaI23ZYMSjmGLKogS997A1whxzOgqTugCvuNSlEz5akZ86QE4myAw2JboDp-DRHrsLiWKCj97Ld2lKTq&new=1
mro(Child(Base1, Base2)) = [Child] + merge(mro(Base1), mro(Base2), [Base1, Base2]) (其中Child继承自Base1, Base2)
mro( B ) = mro( B(A) ) = [B] + merge( mro(A) + [A] ) = [B] + merge( [A] + [A] ) = [B,A]
mro(B) = mro( B(A1, A2, A3 …) ) = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] ) = ...
PS: 计算结果为列表,列表中至少有一个元素即类本身,如上述示例[A1,A2,A3]。merge操做是C3算法的核心。
(参考博客:https://blog.csdn.net/u011467553/article/details/81437780)
+操做:
list_ = ['A'] + ['B'] print(list_) # ['A', 'B']
如计算merge( [E,O], [C,E,F,O], [C] ) 有三个列表 : list1 list2 list3 1 merge不为空,取出第一个列表列表list1的表头E,进行判断 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,于是跳过当前当前列表 2 取出列表list2的表头C,进行判断 C不在各个列表的集合中,于是将C拿出到merge外,并从全部表头删除 merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) 3 进行下一次新的merge操做 ...... merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) = [c] + [E] + merge( [O], [F, 0]) = [c] + [E] + [F] + merge( [O], [0]) = [C] + [E] + [F] + [0]
看看以前的
print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] mro(D(B, C)) = [D] + merge(mro(B(A)), mro(C(A)), [B, C]) = [D] + merge([B] + merge(A(object), [A]), [C] + merge(A(object), [A]), [B, C]) = [D] + merge([B] + merge([A, object], [A]), [C] + merge([A, object], [A]), [B, C]) = [D] + merge([B] + [A, object], [C] + [A, object], [B, C]) = [D] + merge([B, A, object], [C, A, object], [B, C]) = [D] + [B] + merge([A, object], [C, A, object], [C]) = [D] + [B] + [C] + merge([A, object], [A, object]) = [D] + [B] + [C] + [A] + merge([object], [object]) = [D] + [B] + [C] + [A] + [object] = [D, B, C, A, object] = [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
# 备注:O==object, 如何计算mro(A) ? mro(A) = mro(A(B, C)) = [A] + merge(mro(B(D, E)), mro(C(E, F)), [B, C]) = [A] + merge([B] + merge(mro(D(O)), mro(E(O)), [D, E]), [C] + merge(mro(E(O)), mro(F(O)), [E, F]), [B, C]) = [A] + merge([B] + merge([D, O], [E, O], [D, E]), [C] + merge([E, O], [F, O], [E, F]), [B, C]) = [A] + merge([B] + [D, E, 0], [C] + [E, F, O], [B, C]) = [A] + merge([B, D, E, 0], [C, E, F, O], [B, C]) merge([D, O], [E, O], [D, E]) = [D] + merge([O], [E, O], [E]) = [D] + [E] + merge([O], [O]) = [D] + [E] + [O] = [D, E, 0] merge([E, O], [F, O], [E, F]) = [E] + merge([O], [F, O], [F]) = [E] + [F] + merge([O], [O]) = [E] + [F] + [O] = [E, F, O] = [A] + [B] + merge([D, E, 0], [C, E, F, O], [C]) = [A] + [B] + [D] + merge([E, 0], [C, E, F, O], [C]) = [A] + [B] + [D] + [C] + merge([E, 0], [E, F, O]) = [A] + [B] + [D] + [C] + [E] + merge([0], [F, O]) = [A] + [B] + [D] + [C] + [E] + [F]+ merge([0], [O]) = [A] + [B] + [D] + [C] + [E] + [F]+ [O] = [A, B, D, C, E, F, O]
# 以上案例的代码测试 class D: pass class E: pass class F: pass class B(D,E): pass class C(E,F): pass class A(B,C): pass print("从A开始查找:") for s in A.__mro__: print(s) print("从B开始查找:") for s in B.__mro__: print(s) print("从C开始查找:") for s in C.__mro__: print(s) ''' 从A开始查找: <class '__main__.A'> <class '__main__.B'> <class '__main__.D'> <class '__main__.C'> <class '__main__.E'> <class '__main__.F'> <class 'object'> 从B开始查找: <class '__main__.B'> <class '__main__.D'> <class '__main__.E'> <class 'object'> 从C开始查找: <class '__main__.C'> <class '__main__.E'> <class '__main__.F'> <class 'object'> '''
规律总结: “从一至顶,有子先出”
结果参考: