2.7:
经典类,深度优先 class foo()
新式类:广度优先 class foo(object)
3.X:
均是广度优先
python类的体系中如果出现了继承,子类如果没有写自己的初始化方法,会自动继承第一个父类的方法,所以我们需要自己写子类的初始化:
如果像下面的代码:
class A:
def __init__(self):
print("Enter A")
print("Leave A")
class B(A):
def __init__(self):
print("Enter B")
A.__init__(self)
print("Leave B")
class C(A):
def __init__(self):
print("Enter C")
A.__init__(self)
print("Leave C")
class D(A):
def __init__(self):
print("Enter D")
A.__init__(self)
print("Leave D")
class E(B, C, D):
def __init__(self):
print("Enter E")
B.__init__(self)
C.__init__(self)
D.__init__(self)
print("Leave E")
E()
'''会造成公共父类A被调用多次。
正确的办法是使用super,它会把当前的类返回一个父类的对象,注意你在体系中使用了super那么所有的地方都要使用super,
否则可能造成父类多次被调用或者不能调用所有的父类方法(这是由super的机制造成的,具体实现不懂),
super保证所有父类只会执行一次,而且修改代码时也很方便:'''
class A(object):
def __init__(self):
print('Enter A')
self.__test = 0
class C(object):
def __init__(self):
print('Enter C')
super().__init__()
self.__test2 = 3
class D(object):
def __init__(self):
super().__init__()
print('enter D')
class B(A):
def __init__(self):
print('Enter B')
super().__init__()
def set(self):
self.__test = 2
def display(self):
print(dir(self))
class E(C, D):
def __init__(self):
print('Enter E')
super().__init__();
#python中使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承,也叫菱形继承问题)等
#MRO
#MRO即method resolution order,用于判断子类调用的属性来自于哪个父类。
# 在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类
#旧式类查找属性时是深度优先搜索,新式类则是广度优先搜索
#在C++和Java中,使用继承时,子类的构造函数会自动调用父类的构造函数,
# 但在Python中,子类必须显式的在__init__()函数中再次调用父类中的__init__()函数。
########################
# 例2:
# python 普通继承方式和super继承方式
# Python中对象方法第一个参数一般都命名为self(相当于其它语言的this),用于传递对象本身,而在调用的时候则不必显式传递,系统会自动传递。
# 举一个很常见的例子:
class Foo:
def bar(self, message):
print(message)
Foo().bar("Hello, World.")
# 当存在继承关系的时候,有时需要在子类中调用父类的方法,此时最简单的方法是把对象调用转换成类调用,需要注意的是这时self参数需要显式传递,例如:
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
FooParent.bar(self, message)
# 这样做有一些缺点,比如说如果修改了父类名称,那么在子类中会涉及多处修改,另外,Python是允许多继承的语言,
# 如上所示的方法在多继承时就需要重复写多次,显得累赘。为了解决这些问题,Python引入了super()机制,例子代码如下:
# 语法格式:supper(自己的类名,self)
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
super(FooChild, self).bar(message)
# 表面上看 super(FooChild, self).bar(message)方法和FooParent.bar(self, message)方法的结果是一致的,实际上这两种方法的内部处理机制大大不同,当涉及多继承情况时,就会表现出明显的差异来,直接给例子:
# 代码一:
class A:
def __init__(self):
print("Enter A")
print("Leave A")
class B(A):
def __init__(self):
print("Enter B")
A.__init__(self)
print("Leave B")
class C(A):
def __init__(self):
print("Enter C")
A.__init__(self)
print("Leave C")
class D(A):
def __init__(self):
print("Enter D")
A.__init__(self)
print("Leave D")
class E(B, C, D):
def __init__(self):
print("Enter E")
B.__init__(self)
C.__init__(self)
D.__init__(self)
print("Leave E")
E()
# 结果:
#
# Enter E
# Enter B
# Enter A
# Leave A
# Leave B
# Enter C
# Enter A
# Leave A
# Leave C
# Enter D
# Enter A
# Leave A
# Leave D
# Leave E
# 执行顺序很好理解,唯一需要注意的是公共父类A被执行了多次。
# 代码二:
class A:
def __init__(self):
print("Enter A")
print("Leave A")
class B(A):
def __init__(self): #相当于覆盖了父类的构造函数
print("Enter B") #定义属于自己的某些属性
super(B, self).__init__() #super内填写自己的类名。本句相当于继承父类的构造函数
print("Leave B") #定义属于自己的某些属性
print("Leave B")
class C(A):
def __init__(self):
print("Enter C")
super(C, self).__init__() #super内填写自己的类名
print("Leave C")
class D(A):
def __init__(self):
print("Enter D")
super(D, self).__init__() #super内填写自己的类名
print("Leave D")
class E(B, C, D):
def __init__(self):
print("Enter E")
super(E, self).__init__() #super内填写自己的类名
print("Leave E")
E()
# 结果:
# Enter E
# Enter B
# Enter C
# Enter D
# Enter A
# Leave A
# Leave D
# Leave C
# Leave B
# Leave E
#执行E——》执行父类B的__init__ ——》执行父类C的__init__ ——》执行父类D的__init__ ——》执行爷类A的__init__,【B、C、D有三个super(),只执行一个】
# ——》执行D的super()后面的命令 ——》执行C的super()后面的命令 ——》执行B的super()后面的命令 ——》执行E的super()后面的命令
# 在super机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照mro进行的(E.__mro__)。
#在设计类的时候,我们优先考虑通过继承多个类来组合多个类的功能,而不是设计多层次的复杂的继承关系。
########################################
# __slots__的使用
# 作用:限制实例属性只能为指定的属性
# 要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
class Student(object):
__slots__ = ('name','age')
s = Student()
s.age = 12
s.name = 'jack'
s.sex = 'none' #sex没有被放到__slots__中,所以不能绑定sex属性,试图绑定sex将得到AttributeError的错误。