栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

儿童python教程160:Python super()使用注意事项

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

儿童python教程160:Python super()使用注意事项

Python 中,由于基类不会在 __init__() 中被隐式地调用,需要程序员显式调用它们。这种情况下,当程序中包含多重继承的类层次结构时,使用 super 是非常危险的,往往会在类的初始化过程中出现问题。 混用super与显式类调用 分析如下程序,C 类使用了 __init__() 方法调用它的基类,会造成 B 类被调用了 2 次:

class A:

    def __init__(self):

        print("A",end=" ")

        super().__init__()

class B:

    def __init__(self):

        print("B",end=" ")

        super().__init__()

class C(A,B):

    def __init__(self):

        print("C",end=" ")

        A.__init__(self)

        B.__init__(self)

print("MRO:",[x.__name__ for x in C.__mro__])

C()
运行结果为:

MRO: ['C', 'A', 'B', 'object']
C A B B

出现以上这种情况的原因在于,C 的实例调用 A.__init__(self),使得 super(A,self).__init__() 调用了 B.__init__() 方法。换句话说,super 应该被用到整个类的层次结构中。

但是,有时这种层次结构的一部分位于第三方代码中,我们无法确定外部包的这些代码中是否使用 super(),因此,当需要对某个第三方类进行子类化时,**好查看其内部代码以及 MRO 中其他类的内部代码。 不同种类的参数 使用 super 的另一个问题是初始化过程中的参数传递。如果没有相同的签名,一个类怎么能调用其基类的 __init__() 代码呢?这会导致下列问题:

class commonBase:

    def __init__(self):

        print("commonBase")

        super().__init__()



class base1(commonBase):

    def __init__(self):

        print("base1")

        super().__init__()



class base2(commonBase):

    def __init__(self):

        print("base2")

        super().__init__()



class myClass(base1,base2):

    def __init__(self,arg):

        print("my base")

        super().__init__(arg)

myClass(10)
运行结果为:

my base
Traceback (most recent call last):
  File "C:UsersmengmaDesktopdemo.py", line 20, in
    myClass(10)
  File "C:UsersmengmaDesktopdemo.py", line 19, in __init__
    super().__init__(arg)
TypeError: __init__() takes 1 positional argument but 2 were given

一种解决方法是使用 *args 和 **kwargs 包装的参数和关键字参数,这样即使不使用它们,所有的构造函数也会传递所有参数,如下所示:

class commonBase:

    def __init__(self,*args,**kwargs):

        print("commonBase")

        super().__init__()



class base1(commonBase):

    def __init__(self,*args,**kwargs):

        print("base1")

        super().__init__(*args,**kwargs)



class base2(commonBase):

    def __init__(self,*args,**kwargs):

        print("base2")

        super().__init__(*args,**kwargs)



class myClass(base1,base2):

    def __init__(self,arg):

        print("my base")

        super().__init__(arg)

myClass(10)
运行结果为:

my base
base1
base2
commonBase

不过,这是一种很糟糕的解决方法,由于任何参数都可以传入,所有构造函数都可以接受任何类型的参数,这会导致代码变得脆弱。另一种解决方法是在 MyClass 中显式地使用特定类的 __init__() 调用,但这无疑会导致第一种错误。 总结 如果想要避免程序中出现以上的这些问题,这里给出几点建议:
  • 尽可能避免使用多继承,可以使用一些设计模式来替代它;
  • super 的使用必须一致,即在类的层次结构中,要么全部使用 super,要么全不用。混用 super 和传统调用是一种混乱的写法;
  • 如果代码需要兼容 Python 2.x,在 Python 3.x 中应该显式地继承自 object。在 Python 2.x 中,没有指定任何祖先地类都被认定为旧式类。
  • 调用父类时应提前查看类的层次结构,也就是使用类的 __mro__ 属性或者 mro() 方法查看有关类的 MRO。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/805957.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号