簡體   English   中英

在Python中重新定義之前查找__metaclass__

[英]Finding __metaclass__ used before redefinition in Python

我想重新定義一個__metaclass__但是我想回到如果我沒有重新定義就會使用的元類。

class ComponentMetaClass(type):

    def __new__(cls, name, bases, dct):

        return <insert_prev_here>.__new__(cls, name, bases, dct)


class Component(OtherObjects):
     __metaclass__ = ComponentMetaClass

根據我的理解,默認情況下使用的__metaclass__會經歷檢查類范圍內定義的過程,然后是基礎,然后是全局。 通常你會在重定義中使用type,而且通常是全局類型,但是,我的OtherObjects可能已經重新定義了__metaclass__。 所以在使用類型時,我會忽略它們的定義,它們不會運行,對吧?

編輯:請注意,直到運行時我才知道OtherObjects是什么

正如@unutbu所說:“在一個類層次結構中,元類必須是彼此的子類。也就是說,Component的元類必須是OtherObjects的元類的子類。”

這意味着你的問題比你首先要復雜一點 - 不僅你必須從基類調用適當的元類,但你當前的元類也必須從那時起正確地繼承。

(破解一些代碼,面對奇怪的行為,90分鍾后回來)確實很棘手 - 我必須創建一個接收所需元類作為參數的類,並且__call__方法動態生成一個新的元類,修改其基數並添加它的__superclass屬性。

但是這應該做你想要的更多 - 你只需從BaseComponableMeta繼承你的所有元類,並通過元類“__superclass”屬性調用層次結構中的超類:

from itertools import chain

class Meta1(type):
    def __new__(metacls, name, bases, dct):
        print name
        return type.__new__(metacls, name, bases, dct)

class BaseComponableMeta(type):
    def __new__(metacls, *args, **kw):
        return metacls.__superclass.__new__(metacls, *args, **kw)

class ComponentMeta(object):
    def __init__(self, metaclass):
        self.metaclass = metaclass
    def __call__(self, name, bases,dct):
        #retrieves the deepest previous metaclass in the object hierarchy
        bases_list = sorted ((cls for cls in chain(*(base.mro() for base in bases)))
        , key=lambda s: len(type.mro(s.__class__)))   
        previous_metaclass = bases_list[-1].__class__
        # Adds the "__superclass" attribute to the metaclass, so that it can call
        # its bases:
        metaclass_dict = dict(self.metaclass.__dict__).copy()
        new_metaclass_name = self.metaclass.__name__ 
        metaclass_dict["_%s__superclass" % new_metaclass_name] = previous_metaclass
        #dynamicaly generates a new metaclass for this class:
        new_metaclass = type(new_metaclass_name, (previous_metaclass, ), metaclass_dict)
        return new_metaclass(name, bases, dct)

# From here on, example usage:

class ComponableMeta(BaseComponableMeta):
    pass

class NewComponableMeta_1(BaseComponableMeta):
    def __new__(metacls, *args):
        print "Overriding the previous metaclass part 1"
        return metacls.__superclass.__new__(metacls, *args)

class NewComponableMeta_2(BaseComponableMeta):
    def __new__(metacls, *args):
        print "Overriding the previous metaclass part 2"
        return metacls.__superclass.__new__(metacls, *args)

class A(object):
    __metaclass__ = Meta1


class B(A):
    __metaclass__ = ComponentMeta(ComponableMeta)

# trying multiple inheritance, and subclassing the metaclass once:
class C(B, A):
    __metaclass__ = ComponentMeta(NewComponableMeta_1)

# Adding a third metaclass to the chain:
class D(C):
    __metaclass__ = ComponentMeta(NewComponableMeta_2)

# class with a "do nothing" metaclass, which calls its bases metaclasses:  
class E(D):
    __metaclass__ = ComponentMeta(ComponableMeta)

在一個類層次結構中,元類必須是彼此的子類。 也就是說, Component的元類必須是OtherObjects的元類的子類。

如果你不命名__metaclass__Component ,然后元類OtherObjects將默認使用。


如果ComponentMetaClassOtherObjectsMeta都從type繼承(獨立):

class OtherObjectsMeta(type): pass
class ComponentMetaClass(type): pass

class OtherObjects(object):
    __metaclass__ = OtherObjectsMeta

class Component(OtherObjects):
     __metaclass__ = ComponentMetaClass

然后你得到這個錯誤:

TypeError: Error when calling the metaclass bases
    metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

但是如果你將ComponentMetaClass作為OtherObjectsMeta子類

class ComponentMetaClass(OtherObjectsMeta): pass

然后錯誤就消失了。


也許我誤解了你的問題。 如果想要ComponentMetaClass.__new__調用OtherObjectsMeta.__new__ ,那么使用super

class OtherObjectsMeta(type): 
    def __new__(meta, name, bases, dct):
        print('OtherObjectsMeta')
        return super(OtherObjectsMeta,meta).__new__(meta,name,bases,dct)
class ComponentMetaClass(OtherObjectsMeta):
    def __new__(meta, name, bases, dct):
        print('ComponentMetaClass')
        return super(ComponentMetaClass,meta).__new__(meta,name,bases,dct)  

關於使用元類的替代方法,在評論中提到。 使用super

class Base(object):
    def method(self): pass

class Base1(Base):
    def method(self):
        print('Base1')
        super(Base1,self).method()

class Base2(Base): 
    def method(self):
        print('Base2')
        super(Base2,self).method()

class Component(Base1,Base2):
    pass

c = Component()
c.method()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM