动态添加静态方法到Python类

时间:2013-02-01 11:31:09

标签: python oop static-methods

I found非常好的例子如何动态地向类中添加新方法(移植类):

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 个答案:

答案 0 :(得分:18)

您需要做的就是将函数包装在staticmethod()调用中:

say = staticmethod(say)

或将其作为装饰器应用于函数定义:

@staticmethod
def say(host, msg):
    # ...

归结为同样的事情。

记住; @decorator语法只是写target = decorator(target)的语法糖,其中target是装饰对象。

答案 1 :(得分:5)

我在这里看不到静态方法。 say函数需要两个参数,第一个参数host似乎是该类的实例。

所以看起来你只是想把一个新方法附加到一个类。这可以在没有funcToMethod或移植的情况下完成:

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

以上显示了如何将新方法附加到没有funcToMethodtransplant的班级。 funcToMethodtransplant都尝试将函数附加到类的实例而不是类本身。这是错误的,这就是为什么它需要扭曲(比如必须在jimmy中传递jimmy.say2(jimmy, 'Good Bye!')作为参数)才能使它工作。应该在类(例如Patient)上定义方法,而不是在实例上定义(例如jimmy)。

transplant特别可怕。当函数足够时它使用一个类。它使用古老的apply而不是现代self.method(*nargs, **kwargs)语法,并忽略了camelCasing类名的PEP8约定。在它的辩护中,它是十多年前写的。但从根本上说,让它成为良好编程的诅咒的原因在于你只是不需要它。

答案 2 :(得分:0)

以下是有效的方法,即在患者身上采用静态方法,我认为OP需要这样做。

def tell(msg):
   print(msg)

...

funcToMethod(tell, Patient, 'say3')

...

Patient.say3('Bye!')