首页 > 代码库 > python高级编程之超类02:super的缺陷

python高级编程之超类02:super的缺陷

# -*- coding: utf-8 -*-

# python:2.x

__author__ = ‘Administrator‘

#当使用多重继承层次结构时,再使用super的时候是非常危险的,主要是因为类的初始化,基类不在__init__中被隐式调用

#1滥用super和传统调用

#来自james knight(http://funm.net/super-harmful)示例中,类C使用__init__方法调用其基类,这样类B被调用2次

class A(object):

    def __init__(self):

        print ‘A‘

        super(A,self).__init__()

class B(object):

    def __init__(self):

        print ‘B‘

        super(B,self).__init__()

class C(A,B):

    def __init__(self):

        print ‘C‘

        A.__init__(self)

        B.__init__(self)

 

print ‘MRO:‘,[x.__name__ for x in C.__mro__]#MRO: [‘C‘, ‘A‘, ‘B‘, ‘object‘]

C()

"""

C

A

B

B

------------

出现这样的情况是:C实例调用 了A.__init__(self),因而super(A,self).__init__()将调用B构造程序,换句话说,super应该被乃至整个类层次中

问题是有时候这样的层次结构一部分位于第三方代码中,许多由多重继承引入层次调用相关缺陷都可以在JAMES页面上找到,为了避免这样问题,应该问题是在

子类化之前看看__mro__特性,如果它不存在,处理就是一个旧式类,避免使用super可能更安全一些

如下:

"""

from SimpleHTTPServer import SimpleHTTPRequestHandler

#print SimpleHTTPRequestHandler.__mro__AttributeError: class SimpleHTTPRequestHandler has no attribute ‘__mro__‘

"""

如果__mro__存在,则快速地看看每个mro所涉及的类的构造程序代码,如果到处都使用super,那非常好,也可以使用它,否则就试着保持一致性

collections.deque能够被安全地子类化,就可以使用super,因为它直接子类化了object

"""

from collections import deque

print deque.__mro__#(<type ‘collections.deque‘>, <type ‘object‘>)

#randeom.Random是一个存在于_random模块中另一个类封装器

from random import Random

print Random.__mro__#(<class ‘random.Random‘>, <type ‘_random.Random‘>, <type ‘object‘>)

#Zope类,

"""

from zope.app.container.brower.adding import Adding as s

s.__mro__

官方:http://www.zope.com/

有兴趣的朋友可以浏览下

"""

#不同种类参数

#super用法另一个问题是初始化中参数传递,类在没有相同签名的情况下怎么调用其基类的__init__代码呢?

class Bases(object):

    def __init__(self):

        print ‘bases‘

        super(Bases,self).__init__()

class B(Bases):

    def __init__(self):

        print ‘B‘

        super(B,self).__init__()

 

class B1(Bases):

    def __init__(self):

        print ‘b1‘

        super(B1,self).__init__()

 

class MyClass(B,B1):

    def __init__(self,arg):

        print ‘my class arg‘

        super(MyClass,self).__init__(arg)

 

#m=MyClass(10)TypeError: __init__() takes exactly 1 argument (2 given)

#解决方法之下是使用*args,**kw魔法,所有构造程序将传递所有参数,即使不使用它们

class Bb(object):

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

        print ‘b1‘

        super(Bb,self).__init__(*args,**kw)

 

class bb(Bb):

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

        print ‘bb‘

        super(bb,self).__init__(*args,**kw)

 

class bbb(Bb):

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

        print ‘bbb‘

        super(bbb,self).__init__(*args,**kw)

 

class MyclSS(bb,bbb):

    def __init__(self,arg):

        print ‘myclss‘

        super(MyclSS,self).__init__(arg)

 

mm=MyclSS(10)

"""

myclss

bb

bbb

b1

"""

"""

但是这样是一个很糟糕的修复方法,因为它使所有构造程序将接受任何类型参数,导致代码变得很脆弱,因为任何参数被传递并且通过,另一种解决方法是在yclSS

中使用经典的__init__调用,但是这将会导致产生第一种缺陷

"""