问题
When using classmethod to dynamic change the method in subclass, how to dynamic change signatures of method?
example
import inspect
class ModelBase(object):
@classmethod
def method_one(cls, *args):
raise NotImplementedError
@classmethod
def method_two(cls, *args):
return cls.method_one(*args) + 1
class SubClass(ModelBase):
@staticmethod
def method_one(a, b):
return a + b
test = SubClass()
try:
print(inspect.signature(test.method_two))
except AttributeError:
print(inspect.getargspec(test.method_two).args)
I want test.method_two
to get the signatures of test.method_one
. How to rewrite parent class ModelBase
?
I have read about Preserving signatures of decorated functions. In python3.4 +, functools.wraps
helps to preserve signatures of decorated functions. I want to apply it to class method.
when uses functools.wraps
, I need to assign decorated method's name. But how to access decorated method outside classmethod
in this situation?
from functools import wraps
class ModelBase(object):
@classmethod
def method_one(cls, *args):
raise NotImplementedError
@classmethod
def method_two(cls):
@wraps(cls.method_one)
def fun(*args):
return cls.method_one(*args) + 1
return fun
method_two
returns a wrapped function, but I must use it with test.method_two()(*arg)
. This method is not directly.
回答1:
If this is only for introspection purpose you could override __getattribute__
on ModelBase
and every time method_two
is accessed we return a function that has the signature of method_one
.
import inspect
def copy_signature(frm, to):
def wrapper(*args, **kwargs):
return to(*args, **kwargs)
wrapper.__signature__ = inspect.signature(frm)
return wrapper
class ModelBase(object):
@classmethod
def method_one(cls, *args):
raise NotImplementedError
@classmethod
def method_two(cls, *args):
return cls.method_one(*args) + 1
def __getattribute__(self, attr):
value = object.__getattribute__(self, attr)
if attr == 'method_two':
value = copy_signature(frm=self.method_one, to=value)
return value
class SubClass(ModelBase):
@staticmethod
def method_one(a, b):
return a + b
class SubClass2(ModelBase):
@staticmethod
def method_one(a, b, c, *arg):
return a + b
Demo:
>>> test1 = SubClass()
>>> print(inspect.signature(test1.method_two))
(a, b)
>>> test2 = SubClass2()
>>> print(inspect.signature(test2.method_two))
(a, b, c, *arg)
来源:https://stackoverflow.com/questions/45626647/how-to-dynamically-change-signatures-of-method-in-subclass