是否可以为每个函数创建一个“构造函数”或“初始化器”,而不必在类中每个函数的顶部手动编写它?
因此,每次调用一个类中的一个函数时,总是首先调用另一个分配的函数(调用者未知)(在下面的示例中称为pre_check
)。
使用super()
的示例,但是我不得不在每个函数中手动复制它。
class Helper():
def pre_check(self):
print("Helper fcn")
class Parent(Helper):
def __init__(self):
print("Initializer")
def foo(self):
super().pre_check() # <---- new code
# ... existing code here ...
def bar(self):
super().pre_check() # <---- new code
# ... existing code here ...
def many_more_functions(self):
super().pre_check() # <---- new code
# ... existing code here ...
m = Parent()
m.foo()
m.bar()
请注意,__init__
中的Parent
不应运行pre_check
。
答案 0 :(得分:2)
您可以为该类使用装饰器,该装饰器将依次装饰该类中定义的所有公共方法:
def addhelper(helpmethod):
def deco(cls):
def decomethod(method):
def inner(self, *args, **kwargs):
helpmethod(self)
return method(self, *args, **kwargs)
# copy signature, doc and names from the original method
inner.__signature__ = inspect.signature(method)
inner.__doc__ = method.__doc__
inner.__name__ = method.__name__
inner.__qualname__ = method.__qualname__
return inner
# search all methods declared in cls with a name not starting with _
for name, meth in inspect.getmembers(
cls,lambda x: inspect.isfunction(x)
and not x.__name__.startswith('_')
and x.__qualname__.startswith(cls.__name__)):
# replace each method with its decoration
setattr(cls, name, decomethod(meth))
return cls
return deco
class Helper():
def pre_check(self):
print("Helper fcn")
@addhelper(Helper.pre_check)
class Parent(Helper):
def __init__(self):
print("Initializer")
def foo(self):
# super().pre_check() # <----
print('in foo')
def bar(self):
# super().pre_check() # <----
print('in bar')
def many_more_functions(self):
# super().pre_check() # <----
print('in many_more_functions')
我们现在可以使用它:
>>> p = Parent()
Initializer
>>> p.foo()
Helper fcn
in foo
>>> p.bar()
Helper fcn
in bar
>>> p.many_more_functions()
Helper fcn
in many_more_functions
答案 1 :(得分:1)
您可以使用元类并为该元类实例中的每个方法定义一个装饰器
代码:
def decorate(f):
def do_something(self, a):
if (f(self, a) > 18) :
return ("Eligible to vote")
else :
return ("Not eligible to vote")
return do_something
class Meta(type):
def __new__(cls, name, bases, namespace, **kwds):
namespace = {k: v if k.startswith('__') else decorate(v) for k, v in namespace.items()}
return type.__new__(cls, name, bases, namespace)
class MetaInstance(metaclass=Meta):
def foo1(self, val):
return val + 15
def foo2(self, val):
return val + 9
obj1 = MetaInstance()
print(obj1.foo1(5))
print(obj1.foo2(2))
答案 2 :(得分:1)
使用__init_subclass__
更改创建的子类。您可以包装子类的方法:
class Helper():
def __init_subclass__(cls):
for field, value in cls.__dict__.items():
# add additional checks as desired, e.g. exclude __special_methods__
if inspect.isfunction(value) and not getattr(value, 'checked', False):
setattr(cls, field, cls._check(value)) # wrap method
@classmethod
def _check(cls, fcn):
"""Create a wrapper to inspect the arguments passed to methods"""
@functools.wraps(fcn)
def checked_fcn(*args, **kwargs):
print(fcn, "got", args, kwargs)
return fcn(*args, **kwargs)
return checked_fcn
class Parent(Helper):
def __init__(self):
print("Initializer")
def foo(self):
print("Foo")
请注意,这将包装所有方法,包括特殊方法,例如__init__
:
>>> Parent().foo()
<function Parent.__init__ at 0x1029b2378> got (<__main__.Parent object at 0x102c09080>,) {}
Initializer
<function Parent.foo at 0x1029b2158> got (<__main__.Parent object at 0x102c09080>,) {}
Foo
您可以使用任意规则扩展__init_subclass__
的签入,以过滤出函数。例如,field[:2] == field[-2:] == "__"
不包括特殊方法。