Python 2.x中的super()没有args

Sla*_*a V 6 python

试图转换super(B, self).method()成一个简单的好bubble()电话. 做到了,见下文!

在这个例子中是否可以引用B类?

class A(object): pass

class B(A):
    def test(self):
        test2()

class C(B): pass

import inspect
def test2():
    frame = inspect.currentframe().f_back
    cls = frame.[?something here?]
    # cls here should == B (class)

c = C()
c.test()
Run Code Online (Sandbox Code Playgroud)

基本上,C是孩子B,B是孩子A.然后我们创建c类型C.然后调用c.test()实际调用B.test()(通过继承),调用test2().

test2()可以得到父框架frame; 代码引用方法via frame.f_code; self通过frame.f_locals['self']; 但type(frame.f_locals['self'])C(当然),但不B,其中定义的方法.

B什么方法可以得到?

Sla*_*a V 3

找到了一种更短的方法super(B, self).test()->bubble()从下面开始。

(适用于多重继承,不需要参数,正确地处理子类)

解决方案是使用inspect.getmro(type(back_self))(where back_selfis a selffrom callee),然后像clswith一样迭代它method_name in cls.__dict__并验证我们拥有的代码引用是否是此类中的代码引用(在find_class_by_code_object(self)嵌套函数中实现)。

bubble()可以很容易地扩展*args, **kwargs

import inspect
def bubble(*args, **kwargs):
    def find_class_by_code_object(back_self, method_name, code):
        for cls in inspect.getmro(type(back_self)):
            if method_name in cls.__dict__:
                method_fun = getattr(cls, method_name)
                if method_fun.im_func.func_code is code:
                    return cls

    frame = inspect.currentframe().f_back
    back_self = frame.f_locals['self']
    method_name = frame.f_code.co_name

    for _ in xrange(5):
        code = frame.f_code
        cls = find_class_by_code_object(back_self, method_name, code)
        if cls:
            super_ = super(cls, back_self)
            return getattr(super_, method_name)(*args, **kwargs)
        try:
            frame = frame.f_back
        except:
            return



class A(object):
    def test(self):
        print "A.test()"

class B(A):
    def test(self):
        # instead of "super(B, self).test()" we can do
        bubble()

class C(B):
    pass

c = C()
c.test() # works!

b = B()
b.test() # works!
Run Code Online (Sandbox Code Playgroud)

如果有人有更好的想法,让我们听听。

已知错误:(感谢 doublep)如果C.test = B.test-->“无限”递归。尽管子类实际上拥有一种方法似乎不现实,但它是=从父类中继承而来的。

已知 bug2:(感谢 doublep)装饰方法将不起作用(可能无法修复,因为装饰器返回一个闭包)...修复了装饰器问题for _ in xrange(5):...frame = frame.f_back- 将处理最多 5 个装饰器,如果需要则增加。我喜欢Python!

性能比调用差 5 倍super(),但我们谈论的是 200K 调用与每秒 100 万次调用,如果这不在您最紧密的循环中 - 没有理由担心。