python元类,基本构造函数不会被调用

python元类,基本构造函数不会被调用,python,Python,我创建了一个元类,它覆盖默认的init函数,以便添加一个私有变量 问题是,如果我自己不显式调用基类的init函数,它就不会被调用 看看下面的例子 class Base(object): def __init__(self, x, y): self._xvar = x self._yvar = y

我创建了一个元类,它覆盖默认的init函数,以便添加一个私有变量

问题是,如果我自己不显式调用基类的init函数,它就不会被调用

看看下面的例子

class Base(object):                           
    def __init__(self, x, y):                 
        self._xvar = x                        
        self._yvar = y                        
        print("THIS IS THE CONSTRUCTOR", x, y)


class Derived(Base):                          
    pass 


def main():                   
    derived = Derived(11, 20) 
这会打印出来

这是构造函数1120

即使派生类从不调用

super().__init__(x, y)
这是我的元类:

class MetaTemplateContent(type):
    def __new__(mcs, name, base, dct):
        # This is the original init function
        orig_init = dct.get("__init__")

        # this variable will hold all the functions that has a decorator 
        # If the function name is _content_wrapper it will handle static methods as well
        decorators = []
        for _, value in dct.items():
            if isinstance(value, types.FunctionType):
                if value.__name__ == "_content_wrapper":
                    decorators.append(value)
            elif isinstance(value, staticmethod):
                function = value.__func__
                if function.__name__ == "_content_wrapper":
                    decorators.append(function)

        # This is our wrapper init function which will act as a stub
        def init_wrapper(self, *args, **kwargs):
            if orig_init:
                orig_init(self, *args, **kwargs)

            # This is the local variable I want to add to each instance
            # and fill it with all the functions that has the decorator
            self._callbacks = getattr(self, "_callbacks", [])
            self._callbacks.extend(decorators)

        # replace the original init with our stub
        dct["__init__"] = init_wrapper
        return type.__new__(mcs, name, base, dct)
如果我将基类重写为:

class Base(object, metaclass=MetaTemplateContent):
    def __init__(self, x, y):                     
        self._xvar = x                            
        self._yvar = y                            
        print("THIS IS THE CONSTRUCTOR", x, y)    


class Derived(Base):                              
    pass


def main():                  
    derived = Derived(11, 20)
不会打印任何内容,因为基本构造函数从未被调用

但是,将super().init(x,y)添加到派生构造函数将实现以下目的:

class Derived(Base):          
    def __init__(self, x, y): 
        super().__init__(x, y)
但这是多余的,我知道我错过了一些重要的东西。 为什么不调用基类构造函数


这是python 3.5.3

在两种情况下调用基类方法:

  • 你明确地称之为
  • 子类不定义(即重写)方法
  • 没有元类,情况2适用。正如您已经指出的,您的元类为使用该元类的每个类创建一个
    \uuuu init\uuu
    。因此,对于元类,情况2不再适用,基类构造函数也不会被调用

    换句话说,如果一个类定义了
    \uuuu init\uuu
    ,它必须显式地调用基类版本(如果它需要)。您的元类使得每个类都定义了
    \uuuuu init\uuuu
    ,因此,如果您希望调用基
    \uuuuuuu init\uuuu
    ,则必须显式地调用它

    您可以修改元类,使init包装器仅在没有
    orig_init
    时调用超类版本。为此,init包装器需要访问该类,因此您需要交换内容,以便在创建该类后修补init包装器:

    class MetaTemplateContent(type):
        def __new__(mcs, name, base, dct):
            # This is the original init function
            orig_init = dct.get("__init__")
    
            # this variable will hold all the functions that has a decorator 
            # If the function name is _content_wrapper it will handle static methods as well
            decorators = []
            for _, value in dct.items():
                if isinstance(value, types.FunctionType):
                    if value.__name__ == "_content_wrapper":
                        decorators.append(value)
                elif isinstance(value, staticmethod):
                    function = value.__func__
                    if function.__name__ == "_content_wrapper":
                        decorators.append(function)
    
            # make the class first
            cls = type.__new__(mcs, name, base, dct)
    
            # This is our wrapper init function which will act as a stub
            def init_wrapper(self, *args, **kwargs):
                if orig_init:
                    orig_init(self, *args, **kwargs)
                else:
                    super(cls, self).__init__(*args, **kwargs)
    
                # This is the local variable I want to add to each instance
                # and fill it with all the functions that has the decorator
                self._callbacks = getattr(self, "_callbacks", [])
                self._callbacks.extend(decorators)
    
            # replace the original init with our stub
            cls.__init__ = init_wrapper
            return cls
    

    在两种情况下调用基类方法:

  • 你明确地称之为
  • 子类不定义(即重写)方法
  • 没有元类,情况2适用。正如您已经指出的,您的元类为使用该元类的每个类创建一个
    \uuuu init\uuu
    。因此,对于元类,情况2不再适用,基类构造函数也不会被调用

    换句话说,如果一个类定义了
    \uuuu init\uuu
    ,它必须显式地调用基类版本(如果它需要)。您的元类使得每个类都定义了
    \uuuuu init\uuuu
    ,因此,如果您希望调用基
    \uuuuuuu init\uuuu
    ,则必须显式地调用它

    您可以修改元类,使init包装器仅在没有
    orig_init
    时调用超类版本。为此,init包装器需要访问该类,因此您需要交换内容,以便在创建该类后修补init包装器:

    class MetaTemplateContent(type):
        def __new__(mcs, name, base, dct):
            # This is the original init function
            orig_init = dct.get("__init__")
    
            # this variable will hold all the functions that has a decorator 
            # If the function name is _content_wrapper it will handle static methods as well
            decorators = []
            for _, value in dct.items():
                if isinstance(value, types.FunctionType):
                    if value.__name__ == "_content_wrapper":
                        decorators.append(value)
                elif isinstance(value, staticmethod):
                    function = value.__func__
                    if function.__name__ == "_content_wrapper":
                        decorators.append(function)
    
            # make the class first
            cls = type.__new__(mcs, name, base, dct)
    
            # This is our wrapper init function which will act as a stub
            def init_wrapper(self, *args, **kwargs):
                if orig_init:
                    orig_init(self, *args, **kwargs)
                else:
                    super(cls, self).__init__(*args, **kwargs)
    
                # This is the local variable I want to add to each instance
                # and fill it with all the functions that has the decorator
                self._callbacks = getattr(self, "_callbacks", [])
                self._callbacks.extend(decorators)
    
            # replace the original init with our stub
            cls.__init__ = init_wrapper
            return cls