4

我想根据 AorB 中的 init 函数的参数选择在运行时继承的类,A 类或 B 类。我已经尝试过下面的代码,但是这些方法并没有像我希望的那样重载:AorB("B").a() 返回 Aa() 而不是 Ba()。如何选择在运行时继承的类?

更新: 根据下面的反应,我尝试了以下代码。现在我想在 C 类中继承 AorB,这还不行:

class A(object):
    def a(self):
        return "I'm A.a"

    def b(self):
        return "I'm A.b"


class B(object):
    def a(self):
        return "I'm B.a"

    def c(self):
        return "I'm B.c"


def AorB(classname, cache={}):
    if not classname in cache:
        Base = globals()[classname]

        class AorB(Base):
            def __init__(self):
                print(classname)
                Base.__init__(self)
        cache[classname] = AorB
    return cache[classname]()

class C(AorB):                                                                  
    def __init__(self, classname):                                             
        AorB.__init__(classname)

if __name__ == "__main__":
    a = AorB("A")
    print("A.a:", a.a())
    print("A.b:", a.b())

    b = AorB("B")
    print("B.a:", b.a())
    print("B.c:", b.c())

    c = C("B")
    print("C.a:", c.a())
    print("C.c:", c.c())

产量

Traceback (most recent call last):
  File "classtest.py", line 28, in <module>
    class C(AorB):
TypeError: Error when calling the metaclass bases
    function() argument 1 must be code, not str

代替:

A
('A.a:', "I'm A.a")
('A.b:', "I'm A.b")
B
('B.a:', "I'm B.a")
('B.c:', "I'm B.c")
B
('C.a:', "I'm B.a")
('C.c:', "I'm B.c")

4

3 回答 3

6
class A(object):
    def a(self):
        return "I'm A.a"

    def b(self):
        return "I'm A.b"


class B(object):
    def a(self):
        return "I'm B.a"

    def c(self):
        return "I'm B.c"


def make_AorB(Base, classname):
    class AorB(Base):
        def __init__(self):
            print(classname)
            Base.__init__(self)
    return AorB


def make_C(Base, classname):
    class C(Base):
        def __init__(self):
            Base.__init__(self)

        def d(self):
            return "I'm C.d"
    return C


def make_factory(getbase, make_cls):
    def factory(classname):
        if not classname in factory.cache:
            Base = getbase(classname)
            factory.cache[classname] = make_cls(Base, classname)
        return factory.cache[classname]()
    factory.cache = {}
    return factory


AorB = make_factory(lambda classname: globals()[classname], make_AorB)
C = make_factory(lambda classname: AorB.cache[classname], make_C)

if __name__ == "__main__":
    a = AorB("A")
    print(a.__class__, a.__class__.__bases__)
    print("A.a:", a.a())
    print("A.b:", a.b())

    b = AorB("B")
    print(b.__class__, b.__class__.__bases__)
    print("B.a:", b.a())
    print("B.c:", b.c())

    c = C("B")
    print(c.__class__, c.__class__.__bases__)
    print("C.a:", c.a())
    print("C.c:", c.c())
    print("C.d:", c.d())

产量

A
(<class '__main__.AorB'>, (<class '__main__.A'>,))
('A.a:', "I'm A.a")
('A.b:', "I'm A.b")
B
(<class '__main__.AorB'>, (<class '__main__.B'>,))
('B.a:', "I'm B.a")
('B.c:', "I'm B.c")
B
(<class '__main__.C'>, (<class '__main__.AorB'>,))
('C.a:', "I'm B.a")
('C.c:', "I'm B.c")
('C.d:', "I'm C.d")
于 2013-03-05T11:18:47.210 回答
0

这是您的代码的问题(更新后)C 不能从 AorB 继承,这是一个函数:

class C(AorB):
    def __init__(self, classname):
        AorB.__init__(classname)

由于您想在对 C 的调用中使用基类,因此您可以让 C 成为依次调用 AorB 的函数:

def C(basename):
    return AorB(basename)
于 2013-03-06T13:24:22.473 回答
0

我不是 100% 确定(您的用例),但您可以使用 的变体type来执行以下操作(其中某些条件是有条件的):

def produce_C(kls, *args, **kwdargs):
    return type('C', (globals()[kls],), {})(*args, **kwdargs)

虽然这会混淆类型系统......(可能将类名修改为C_from_AC_from_B- 但是呃)

于 2013-03-05T13:42:12.190 回答