如何在python中为类动态创建类方法

use*_*508 58 python static-methods metaprogramming class setattr

如果我定义一个小python程序

class a():
    def _func(self):
        return "asdf"

    # Not sure what to resplace __init__ with so that a.func will return asdf
    def __init__(self, *args, **kwargs):
         setattr(self, 'func', classmethod(self._func))

if __name__ == "__main__":
    a.func
Run Code Online (Sandbox Code Playgroud)

我收到回溯错误

Traceback (most recent call last):
  File "setattr_static.py", line 9, in <module>
    a.func
AttributeError: class a has no attribute 'func'
Run Code Online (Sandbox Code Playgroud)

我想弄清楚的是,如何在不实例化对象的情况下动态地将类方法设置为类?


编辑:

这个问题的答案是

class a():
    pass

def func(cls, some_other_argument):
    return some_other_argument

setattr(a, 'func', classmethod(func))

if __name__ == "__main__":
    print(a.func)
    print(a.func("asdf"))
Run Code Online (Sandbox Code Playgroud)

返回以下输出

<bound method type.func of <class '__main__.a'>>
asdf
Run Code Online (Sandbox Code Playgroud)

tde*_*ney 64

您可以通过简单分配给类对象或通过类对象上的setattr动态地将类方法添加到类中.在这里,我使用python约定,类以大写字母开头,以减少混淆:

# define a class object (your class may be more complicated than this...)
class A(object):
    pass

# a class method takes the class object as its first variable
def func(cls):
    print 'I am a class method'

# you can just add it to the class if you already know the name you want to use
A.func = classmethod(func)

# or you can auto-generate the name and set it this way
the_name = 'other_func' 
setattr(A, the_name, classmethod(func))
Run Code Online (Sandbox Code Playgroud)


And*_*ark 8

这里有几个问题:

  • __init__仅在您创建实例时运行,例如obj = a().这意味着当你这样做时a.func,setattr()呼叫没有发生
  • 您无法直接从该类的方法中访问类的属性,因此不需要_func在内部使用,而是__init__需要使用self._funcself.__class__._func
  • self将是一个实例a,如果你在实例上设置一个属性,它只能用于该实例,而不是该类.所以即使在调用之后setattr(self, 'func', self._func),a.func也会引发一个AttributeError
  • 使用staticmethod你不会做的任何事情,staticmethod将返回一个结果函数,它不会修改参数.所以相反,你会想要类似的东西setattr(self, 'func', staticmethod(self._func))(但考虑到上述评论,这仍然无法奏效)

所以现在的问题是,你究竟想做什么?如果您真的想在初始化实例时向类添加属性,则可以执行以下操作:

class a():
    def _func(self):
        return "asdf"

    def __init__(self, *args, **kwargs):
        setattr(self.__class__, 'func', staticmethod(self._func))

if __name__ == '__main__':
    obj = a()
    a.func
    a.func()
Run Code Online (Sandbox Code Playgroud)

然而,这仍然有点奇怪.现在您可以a.func毫无问题地访问和调用它,但self参数a.func将始终是最近创建的实例a.我真的无法想到将实例方法_func()转换为类的静态方法或类方法的任何理智方法.

既然您正在尝试动态地向类中添加一个函数,那么下面的内容可能更接近您实际尝试的内容?

class a():
    pass

def _func():
    return "asdf"

a.func = staticmethod(_func)  # or setattr(a, 'func', staticmethod(_func))

if __name__ == '__main__':
    a.func
    a.func()
Run Code Online (Sandbox Code Playgroud)