代码之家  ›  专栏  ›  技术社区  ›  Slava V

python 2.x中的super()不带参数

  •  6
  • Slava V  · 技术社区  · 15 年前

    试图转换 super(B, self).method() 变成一个简单的好人 bubble() 打电话。 做到了吗? , see below !

    在本例中是否可以引用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()
    

    基本上, C 是孩子 B , 是孩子 A . 然后我们创造 c 类型的 C . 然后打电话给 c.test() 实际调用 B.test() (通过继承),它调用 test2() .

    Test2() 可以获取父帧 frame ;方法的代码引用 frame.f_code ; self 通过 frame.f_locals['self'] 但是 type(frame.f_locals['self']) C (当然),但不是 ,其中定义了方法。

    有什么办法 ?

    3 回复  |  直到 15 年前
        1
  •  3
  •   Slava V    15 年前

    找到了一个更短的方法 super(B, self).test() -gt; bubble() 从下面。

    (与多重继承一起工作,不需要参数,correcly与子类一起工作)

    解决办法是 inspect.getmro(type(back_self)) (何处) back_self 是一个 self ,然后将其迭代为 cls 具有 method_name in cls.__dict__ 并验证我们拥有的代码引用是否是该类中的代码引用(在 find_class_by_code_object(self) 嵌套函数)。

    冒泡() 可以很容易地扩展 *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!
    

    如果有人有更好的主意,让我们听听。

    已知错误: (多谢)如果 C.test = B.test -->“无限”递归。虽然这看起来不现实,儿童班实际上有一个方法,这已经 = “是父母的孩子。

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

    性能比 super() 打电话,但我们说的是每秒20万个电话,而不是100万个电话,如果这不是你最紧张的循环-没有理由担心。

        2
  •  0
  •   Wolph    15 年前

    尽管此代码不应用于任何正常目的。为了回答这个问题,这里有一些有用的东西;)

    import inspect
    
    def test2():
        funcname = inspect.stack()[1][3]
        frame = inspect.currentframe().f_back
        self = frame.f_locals['self']
    
        return contains(self.__class__, funcname)
    
    def contains(class_, funcname):
        if funcname in class_.__dict__:
            return class_
    
        for class_ in class_.__bases__:
            class_ = contains(class_, funcname)
            if class_:
                return class_
    
        3
  •  -1
  •   doublep    15 年前

    由于python中的函数没有绑定到类[1],所以一般的答案是“不可能”。 但是,对于遵循属性标准命名约定的非静态函数,您可以尝试

    inspect.currentframe().f_back.f_locals['self']。

    [1]例如,您可以:

    class X: pass
    X.foo = (lambda self: None)
    

    编辑:

    我设法提出了一个已经出现在这个问题上的方法:-/。但是,我仍然很好奇您是如何做到这一点的,因为我仍然确定函数没有绑定到python中的类。