动态添加静态方法到Python类
我在这里找到一个很好的例子,教我们怎么动态地给一个类添加新方法(也就是把方法“移植”到类里):
def say(host, msg):
print '%s says %s' % (host.name, msg)
def funcToMethod(func, clas, method_name=None):
setattr(clas, method_name or func.__name__, func)
class transplant:
def __init__(self, method, host, method_name=None):
self.host = host
self.method = method
setattr(host, method_name or method.__name__, self)
def __call__(self, *args, **kwargs):
nargs = [self.host]
nargs.extend(args)
return apply(self.method, nargs, kwargs)
class Patient:
def __init__(self, name):
self.name = name
if __name__ == '__main__':
jimmy = Patient('Jimmy')
transplant(say, jimmy, 'say1')
funcToMethod(say, jimmy, 'say2')
jimmy.say1('Hello')
jimmy.say2(jimmy, 'Good Bye!')
但是我不太明白,怎么修改这个例子来添加静态方法。有人能帮我吗?
3 个回答
好的,下面的代码可以正常工作,也就是说它在Patient类上添加了一个静态方法,我觉得这正是提问者想要的。
def tell(msg):
print(msg)
...
funcToMethod(tell, Patient, 'say3')
...
Patient.say3('Bye!')
我在这里没有看到静态方法。say
这个函数需要两个参数,而第一个参数host
看起来是这个类的实例。
所以看起来你只是想给一个类添加一个新方法。其实可以不使用funcToMethod或transplant来做到这一点:
def say(self, msg):
print '%s says %s' % (self.name, msg)
class Patient:
def __init__(self, name):
self.name = name
if __name__ == '__main__':
jimmy = Patient('Jimmy')
Patient.say = say
jimmy.say('Hello')
这样就可以了
Jimmy says Hello
如果你想添加一个静态方法,那么正如MartijnPieters所说的,使用staticmethod
装饰器:
def tell(msg):
print(msg)
if __name__ == '__main__':
jimmy = Patient('Jimmy')
Patient.tell = staticmethod(tell)
jimmy.tell('Goodbye')
这样就可以了
Goodbye
上面的内容展示了如何在不使用funcToMethod
或transplant
的情况下,将新方法添加到一个类中。funcToMethod
和transplant
都是试图将函数附加到类的实例上,而不是类本身。这种做法是错误的,所以需要一些复杂的操作(比如在jimmy.say2(jimmy, 'Good Bye!')
中传递jimmy
作为参数)才能让它工作。方法应该在类上定义(例如Patient
),而不是在实例上(例如jimmy
)。
transplant
特别糟糕。它使用了一个类,而其实用一个函数就足够了。它使用了过时的apply
,而不是现代的self.method(*nargs, **kwargs)
语法,并且忽略了PEP8关于类名使用驼峰命名法的规范。为了给它辩护,它是在十多年前写的。但从根本上说,它之所以被认为是糟糕编程的反面,是因为你根本不需要它。
你只需要把这个函数放在一个 staticmethod()
的调用里就可以了:
say = staticmethod(say)
或者把它作为装饰器应用到函数定义上:
@staticmethod
def say(host, msg):
# ...
这两种方式其实是一样的。
记住;@decorator
这种写法只是为了让代码看起来更简洁,其实它的意思是 target = decorator(target)
,这里的 target
就是被装饰的对象。