使类方法识别它正在运行的类上下文

时间:2012-01-23 06:54:28

标签: python

我需要通过折叠一个方法来重构现有代码,该方法可以在彼此继承的各种类别之间复制粘贴到一个方法中。 所以我制作了以下代码:

class A(object):
    def rec(self):
        return 1

class B(A):
    def rec(self):
        return self.rec_gen(B)

    def rec_gen(self, rec_class):
        return super(rec_class, self).rec() + 1

class C(B):
    def rec(self):
        return self.rec_gen(C)

if __name__=='__main__':
    b = B(); c = C()
    print c.rec()
    print b.rec()

输出:

3
2

让我感到困扰的是,在'rec'方法中,我需要告诉'rec_gen'它正在运行的类的上下文。 “rec_gen”有没有办法在运行时自行解决?

3 个答案:

答案 0 :(得分:4)

此功能已添加到Python 3中 - 请参阅PEP 3135。简而言之:

class B(A):
    def rec(self):
        return super().rec() + 1

我认为您已经创建了错综复杂的rec() / rec_gen()设置,因为您无法自动找到该类,但是如果您想要它,则无论如何都应该有效:

class A(object):
    def rec(self):
        return 1

class B(A):
    def rec(self):
        # __class__ is a cell that is only created if super() is in the method
        super()
        return self.rec_gen(__class__)

    def rec_gen(self, rec_class):
        return super(rec_class, self).rec() + 1

class C(B):
    def rec(self):
        # __class__ is a cell that is only created if super() is in the method
        super()
        return self.rec_gen(__class__)

Python 2中最简单的解决方案是使用私有成员来保存super对象:

class B(A):
    def __init__(self):
        self.__super = super(B)

    def rec(self):
        return self.__super.rec() + 1

但是仍然需要在一个地方指定实际的类,如果你碰巧在类层次结构中有两个同名的类(例如来自不同的模块),这个方法就会破坏。

在PEP 3135存在之前,我们有几个人为Python 2自动解析配方 - 我的方法是self.super on ActiveState。基本上,它允许以下内容:

class B(A, autosuper):
    def rec(self):
        return self.super().rec() + 1

或者您正在调用具有相同名称的父方法(最常见的情况):

class B(A, autosuper):
    def rec(self):
        return self.super() + 1

对此方法的警告:

  1. 这很慢。我有一个版本坐在某处进行字节码操作,以提高速度。

  2. 这与PEP 3135不一致(虽然它是一个阶段的Python 3超级提案)。

  3. 这很复杂。

  4. 这是一个混合基类。

  5. 我不知道上述内容是否能满足您的要求。虽然你可以找到你所在的课程并将其传递给rec_gen(),但是对于食谱进行了一些小改动 - 基本上将_getSuper()中的类查找代码提取到自己的方法中。

答案 1 :(得分:1)

python 2.x的另一种解决方案是使用元类在所有子类中自动定义rec方法:

class RecGen(type):
    def __new__(cls, name, bases, dct):
        new_cls = super(RecGen, cls).__new__(cls, name, bases, dct)

        if bases != (object,):
            def rec(self):
                return super(new_cls, self).rec() + 1
            new_cls.rec = rec

        return new_cls

class A(object):
    __metaclass__ = RecGen
    def rec(self):
        return 1

class B(A):
    pass

class C(B):
    pass

请注意,如果您只是尝试获得类似父类的数量,那么直接使用self.__class__.__mro__会更容易:

class A(object):
    def rec(self):
        return len(self.__class__.__mro__)-1

class B(A):
    pass

class C(B):
    pass

答案 2 :(得分:0)

我不确定你想要实现什么,但是如果它只是为每个类返回一个不同的常量值的方法,那么使用类属性来存储该值。您的示例中并不清楚您需要去super()附近的任何地方。

class A(object):
    REC = 1
    def rec(self):
        return self.REC

class B(A):
    REC = 2

class C(B):
    REC = 3

if __name__=='__main__':
    b = B(); c = C()
    print c.rec()
    print b.rec()