欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python super()和classmethod

程序员文章站 2024-01-12 08:56:22
python super()和classmethod,@(python)。 super(type, obj) 子类中定义了同父类同名的函数后,需要显示调用父类函数时,可以通过...

python super()和classmethod,@(python)。

super(type, obj)

子类中定义了同父类同名的函数后,需要显示调用父类函数时,可以通过 super,也可以直接通过父类名,建议使用 super,比如在初始化函数中调用父类初始化方法,尤其在多重继承的情况下
看看例子:

#!/usr/bin/env python
# coding=utf-8

class a:
    def __init__(self):
        print("enter a")
        super(a, self).__init__()
        print("leave a")

class b:
    def __init__(self):
        print("enter b")
        #super(b, self).__init__()
        print("leave b")

class ca(a):
    def __init__(self):
        print("enter ca")
        super(ca,self).__init__()
        print("leave ca")


class caa(ca, a):
    def __init__(self):
        print("enter caa")
        super(caa,self).__init__()
        print("leave caa")

class cb(b):
    def __init__(self):
        print("enter cb")
        b.__init__(self)
        print("leave cb")


class cbb(cb, b):
    def __init__(self):
        print("enter cbb")
        cb.__init__(self)
        b.__init__(self)
        print("leave cbb")


if __name__ == "__main__":
    print("- new object caa")
    caa = caa()
    print("- new object cbb")
    cbb = cbb()

上述列子中,两组类关系:
caa->ca->a 采用 super 调用父类函数
cbb->cb->b 直接通过父类名调用其行数

对比运行结果

lcd@ubuntu:~/learn/python$ python3 supper_class.py 
- new object caa
enter caa
enter ca
enter a
leave a
leave ca
leave caa
- new object cbb
enter cbb
enter cb
enter b   
leave b
leave cb
enter b   -->重复调用了
leave b
leave cbb

可以看到,使用super, python 不止保证继承时按顺序调用父类初始化,而且保证每一个类不被重复调用。

classsmethod

python 有三种方式定义类方法:
如下面例子类 a 定义的三个方法,
* 常规方式定义了 foo,同对象实例绑定,通过对象调用的时候,会通过隐式 self 参数传递类对象实例子;如果直接通过类调用,需要显示传递类实例;
* @classmethod 方式定义了 class_foo 方法,同类绑定,可以直接通过类名可以直接调用,调用时通过 cls 隐式参数传递类对象。
* @staticmethod 方式定义的方法和普通函数一样,没有绑定对象,没有传递隐式参,可以通过类实例或者类调用。(属于类的函数,但是不需要访问类,通过后续子类覆盖,更好地组织代码)

#!/usr/bin/env python
# coding=utf-8
# by orientlu

class a(object):
    def __init__(self):
        print("a init")
        super().__init__()

    def foo(self, x):
        '''绑定对象'''
        print("a exec foo (%s, %d)" %(self, x))

    @classmethod
    def class_foo(cls, x):
        '''绑定类'''
        print("exec class_foo (%s, %d)" %(cls, x))

    @staticmethod
    def static_foo(x):
        '''没有绑定类,对象'''
        print("exec static_foo (%d)" %(x))

class b(object):
    def foo(self, x):
        '''绑定对象'''
        print("exec foo (%s, %d)" %(self, x))

    @classmethod
    def test_class_foo(cls, x):
        '''绑定类'''
        print("exec test_class_foo -2- (%s, %d)" %(cls, x))

    def test_class_foo(self, x):
        '''后面方法覆盖前面的同名方法'''
        print("exec test_class_foo -1- (%s, %d)" %(self, x))


class aa(a):
    def __init__(self):
        print("aa int")

    def foo(self, x):
        '''覆盖了父类函数'''
        print("aa exec foo (%s, %d)" %(self, x))


class c(aa):
    def __init__(self):
        '''子类定义了方法覆盖了父类,通过super调用到父类函数'''
        super().__init__()
        print("c init")

    def c_fun1(self):
        '''子类没有定义的函数,直接调用父类函数'''
        self.foo(1)

if __name__ == "__main__":

    print("***********************************")
    print("-------")
    a = a()
    a.foo(1)
    a.class_foo(1)
    a.static_foo(1)

    print("-------")
    a.foo(a, 1)
    a.class_foo(1)
    a.static_foo(1)

    print("***********************************")
    b = b()
    b.test_class_foo(1)
    # 以下调用出错,因为classmethod被后面的函数所覆盖了
    #b.test_class_foo(1)
    # 实际存在是后面定义的函数
    b.test_class_foo(b, 1)

    print("***********************************")
    c = c()
    c.c_fun1()

上述代码在 python3 环境下运行的输出 :

***********************************
-------
a init
a exec foo (<__main__.a object at 0x7f6af4c36ac8>, 1)
exec class_foo (, 1)
exec static_foo (1)
-------
a exec foo (<__main__.a object at 0x7f6af4c36ac8>, 1)
exec class_foo (, 1)
exec static_foo (1)
***********************************
exec test_class_foo -1- (<__main__.b object at 0x7f6af4c36b38>, 1)
exec test_class_foo -1- (<__main__.b object at 0x7f6af4c36b38>, 1)
***********************************
aa int
c init
aa exec foo (<__main__.c object at 0x7f6af4c36b70>, 1)