Мульти наследование от фабрик метаклассов - PullRequest
0 голосов
/ 20 января 2012

Я хочу SuperClass12 наследовать от SuperClass1 и SuperClass2:

def getClass1(): 
    class MyMetaClass1(type):
        def __new__(cls, name, bases, dct):
            print dct.get("Attr","")+"Meta1"
            return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)
    return MyMetaClass1

def getClass2(): 
    class MyMetaClass2(type):
        def __new__(cls, name, bases, dct):
            print dct.get("Attr","")+"Meta2"
            return super(MyMetaClass2, cls).__new__(cls, name, bases, dct)
    return MyMetaClass2    

class SuperClass1():
    __metaclass__ = getClass1()
    def fun1(self):
        pass

class SuperClass2():
    __metaclass__ = getClass2()
    def fun2(self):
        pass

class MyClass1(SuperClass1):
    Attr = "MC1"

class MyClass2(SuperClass2):
    Attr = "MC2"

def getClass12(): 
    class myMultiMeta(getClass1(),getClass2()):
        pass
    return myMultiMeta

class SuperClass12(SuperClass1,SuperClass2):
#class SuperClass12(): gives no errors in class construction but then 
#fun1() and fun2() are not members of SuperClass12. 
    __metaclass__ = getClass12()

class MyClass12(SuperClass12):
    Attr = "MC12"

Instance = MyClass12()
Instance.fun1()
Instance.fun2()

К сожалению, у меня есть эта ошибка:

TypeError: Ошибка при вызовеконфликт метаклассов баз метаклассов: метакласс производного класса должен быть (нестрогим) подклассом метаклассов всех его баз

, но я не могу понять почему, поскольку метакласс myMultiMetaМой производный класс SuperClass12 действительно является подклассом метаклассов (MyMetaClass1,MyMetaClass2) всех его основ (SuperClass1,SUperClass2).

Ответы [ 4 ]

3 голосов
/ 20 января 2012

Как отметил Майкл Мерикель, функции getClass() должны возвращать один и тот же объект при каждом вызове, чтобы ваше наследование работало.Класс, который просто идентичен, недостаточно хорош.Вот один из способов сделать это: использовать класс, чтобы он действовал как ваши getClass() функции.Поскольку определение класса выполняется только один раз, MyMetaClass1 всегда является одним и тем же объектом при возврате.

class getClass1(object):
    class MyMetaClass1(type):
        def __new__(cls, name, bases, dct):
            print dct.get("Attr","")+"Meta1"
            return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)
    class __metaclass__(type):
        def __call__(cls):
            return cls.MyMetaClass1

Вы также можете сделать это так, используя реальную функцию и используя изменяемый аргумент по умолчанию для кэшированияэкземпляр класса:

def getClass1(cls=[]):
    if not cls:
        class MyMetaClass1(type):
            def __new__(cls, name, bases, dct):
                print dct.get("Attr","")+"Meta1"
                return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)
        cls.append(MyMetaClass1)
    return cls[0]

Здесь вы заметите повторяющуюся тему: злоупотребление функциями Python.:-) Это, как правило, признак того, что вы делаете что-то, что может быть сделано лучше другим способом.Например, почему вы используете фабрики, а не просто определяете класс обычным способом?Я видел, что фабрики классов имеют какое-то применение, но я не думаю, что когда-либо видел фабрику метаклассов в дикой природе.

2 голосов
/ 20 января 2012

Помните, что getClass1 и getClass2 возвращают новый экземпляр метакласса.Таким образом, когда вы устанавливаете __metaclass__ = getClass1(), это метакласс, отличный от наследуемого myMultiMeta.

1 голос
/ 20 января 2012

Это то, что вы хотите?

class MyMetaClass1(type):
    def __new__(cls, name, bases, dct):
        print dct.get("Attr","")+"Meta1"
        return super(MyMetaClass1, cls).__new__(cls, name, bases, dct)

class MyMetaClass2(type):
    def __new__(cls, name, bases, dct):
        print dct.get("Attr","")+"Meta2"
        return super(MyMetaClass2, cls).__new__(cls, name, bases, dct)

class SuperClass1():
    __metaclass__ = MyMetaClass1
    def fun1(self):
        pass

class SuperClass2():
    __metaclass__ = MyMetaClass2
    def fun2(self):
        pass

class MyClass1(SuperClass1):
    Attr = "MC1"

class MyClass2(SuperClass2):
    Attr = "MC2"

class MyMultiMeta(MyMetaClass1, MyMetaClass2):
    pass

class SuperClass12(SuperClass1, SuperClass2):
#class SuperClass12(): gives no errors in class construction but then 
#fun1() and fun2() are not members of SuperClass12. 
    __metaclass__ = MyMultiMeta

class MyClass12(SuperClass12):
    Attr = "MC12"

Instance = MyClass12()
Instance.fun1()
Instance.fun2()

Пробег:

vic@ubuntu:~/Desktop$ python test.py 
Meta1
Meta2
MC1Meta1
MC2Meta2
Meta1
Meta2
MC12Meta1
MC12Meta2
vic@ubuntu:~/Desktop$ 
0 голосов
/ 20 января 2012

Благодарю, кто, дав несколько ответов, помог мне:

def getClass12(): 
     class myMultiMeta(SuperClass1.__metaclass__,SuperClass2.__metaclass__):
         pass
     return myMultiMeta
 class SuperClass12(SuperClass1,SuperClass2):
     __metaclass__ = getClass12()

- это неплохое решение!

...