Python 编程要点 -- 类方法,静态方法,实例方法,mro机制

来源:互联网 发布:python分布式爬虫系统 编辑:程序博客网 时间:2024/05/21 04:00

Python 类方法,静态方法,实例方法

类方法,静态方法,实例方法都可以通过类名和实例对象访问,如下:
需要注意点一点是类名访问实例方法的时候必须传递实例对象。
注意:函数 只能由类名访问(Python3),Python2不能访问。
注意:申明静态方法使用@staticmethod 并且不用加类名或者实例对象作为参数
注意:申明类方法使用@classmethod 并且需要加上cls作为方法参数

class A(object):    @classmethod    def cls_func(cls):        print "classmethod"    @staticmethod    def static_func():        print("staticmethod")    def instance_func(self):        print("instance_func")    def common_func():        print("common func")a = A()a.cls_func()a.static_func()a.instance_func()A.cls_func()A.static_func()A.instance_func(a)#Error python2 中类名不能访问函数,但是Python3可以访问#A.common_func()#Error Python2/3中都不能使用实例访问函数#a.common_func()>>classmethodstaticmethodinstance_funcclassmethodstaticmethodinstance_funccommon func

子类中访问父类的方法,以及多重继承的问题

在python中子类访问父类的方法有两种方式:

1.使用类名调用类的方法:

class A(object):    def __init__(self):        print("Call A __init__!")class B(A):    def __init__(self):        print("Call B __init__!")        A.__init__(self)b = B()>>Call B __init__!Call A __init__!

2.使用super调用父类的方法:

class A(object):    def __init__(self):        print("Call A __init__!")class B(A):    def __init__(self):        print("Call B __init__!")        super(B, self).__init__()b = B()>>Call B __init__!Call A __init__!

方法一更直观。推荐使用方法一进行父类的初始化。
注意!注意!注意!这里纠正一下:有的地方说方法二可以一次初始化所有超类,该说法是错误的。super并不是像Java或者其他语言一样调用所有父类的构造方法,它是调用的__class__.mro()的下一个类调用构造方法 如下:
下面的函数并不会调用B类的构造函数,因为 __class__.mro()指向的下一个类是A。

class A(object):    def __init__(self, age=1):        print("A __init__!")        self.age = ageclass B(object):    def __init__(self, name=""):        print("B __init__!")        self.name = nameclass C(A,B):    def __init__(self):        print("C __init__!")        super(C, self).__init__()c = C()>>C __init__!A __init__![<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

就算调用两次super也不会初始化B的构造函数,如下:
反而它只是调用了两次A类的构造函数而已。

class A(object):    def __init__(self, age=1):        print("A __init__!")        self.age = ageclass B(object):    def __init__(self, name=""):        print("B __init__!")        self.name = nameclass C(A,B):    def __init__(self):        print("C __init__!")        super(C, self).__init__()        super(C, self).__init__()c = C()>>C __init__!A __init__!A __init__![<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

下面列举一个更加复杂的例子来说明:
如果是想当然以为super是调用父类的构造函数那么输出的顺序应该是

>>B __init__!A __init__!A leaving!B leaving!C __init__!A __init__!A leaving!C leaving !

然而情况是:当调用D的初始化函数时按照D类的mro()顺序来选择下一个类的初始化。
这里还可以看出如果你没有写__init__函数,那么python默认的方式是通过super初始化父类

class A(object):    def __init__(self, age=0):        print("A __init__!")        self.age = age         print("A leaving!")class B(A):    def __init__(self, name=""):        print("B __init__!")        super(B, self).__init__()        self.name = name        print("B leaving!")class C(A):    def __init__(self):        print("C __init__!")        super(C, self).__init__()        print("C leaving !")class D(B, C):     passd = D() print(d.__class__.mro())>>B __init__!C __init__!A __init__!A leaving!C leaving !B leaving![<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>]

结论是:当你的程序里面含有多重继承存在的时候千万要注意尽量避免使用super的方式,而应该直接使用类名初始化的方式,多写几行代码比出错来的划算!上面的例子改写为方法一的方式如下:

class A(object):    def __init__(self, age=0):        print("A __init__!")        self.age = age         print("A leaving!")class B(A):    def __init__(self, name=""):        print("B __init__!")        A.__init__(self, age=12)        self.name = name        print("B leaving!")class C(A):    def __init__(self):        print("C __init__!")        A.__init__(self, age=14)        print("C leaving !")class D(B, C):    def __init__(self):        print("D __init__!")        B.__init__(self)        C.__init__(self)        print("D leaving!")d = D() >>D __init__!B __init__!A __init__!A leaving!B leaving!C __init__!A __init__!A leaving!C leaving !D leaving!

Python mro 的顺序问题

首先mro是按照深度优先的计算方式,重复类只保留最后一个这是什么意思呢?就拿上面的例子来说深度优先的原则的话就应该是[D, B, A, object, C, A, object] 这样一个顺序,但是重复类只保留最后一个的原则决定了它应该是[D, B, C, A, object]这样的。所以这样就很好的理解了super为什么会表现出那样的方式。
下面再给出一个例子说明:

class A(object):    def __init__(self, age=0):        print("A __init__!")        self.age = age         print("A leaving!")    def func(self):        print("A func call!")class B(A):    def __init__(self, name=""):        print("B __init__!")        A.__init__(self, age=12)        self.name = name        print("B leaving!")class C(A):    def __init__(self):        print("C __init__!")        A.__init__(self, age=14)        print("C leaving !")    def func(self):        print("C func call!")class D(B, C):    def __init__(self):        print("D __init__!")        B.__init__(self)        C.__init__(self)        print("D leaving!")d = D()d.func()>>D __init__!B __init__!A __init__!A leaving!B leaving!C __init__!A __init__!A leaving!C leaving !D leaving!C func call!

以上程序的输出是C func 被调用了,也证实了mro的顺序规则。

原创粉丝点击