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