为类实例动态创建方法

时间:2017-03-07 19:55:30

标签: python

以下程序无法创建类

的功能
class MyClass(object):
    def __init__(self, name=""):
        self.name = name

    def read_name(self):
        return self.name

# First argument should be a ref to class
def callback(fcn, arg):
    fcn.name=arg

# Create a instance of class
a = MyClass("Blue")

# Lets add new member functions
setattr(a, 'callback1', callback)  
setattr(a, 'callback2', callback)  

print a.read_name()

print a.callback1("purple")    #! FAILS
print a.callback2("cyan")  #! FAILS

自动创建类成员函数的正确方法是什么?

我想创建N' N'回调函数,它们都会修改一些常见/不常见的类数据(共享字典)

编辑1

我希望收集N' N'通过传递回调函数来分离/并行线程。我事先不知道我需要多少个回调函数,因此我想在飞行中创建它们。

编辑2

我有一个字典(d),我存储不同进程的信息。在回调中访问字典(d)。但是因为在不同的线程上调用相同的callback函数,所以字典数据会出现乱码。作为一个quickfix,我想到了创建单独的回调。

3 个答案:

答案 0 :(得分:3)

如果您知道自己在做什么,就想尝试

import types
setattr(a, 'callback1', types.MethodType(callback, a, MyClass))

答案 1 :(得分:1)

您无法向实例添加类方法;你必须把它添加到班级:

setattr(MyClass, 'callback1', callback)

但这仍然是一个糟糕的主意。你为什么想要这个功能?

编辑:改为将回调放在容器中:

class MyClass(object):
    def __init__(self, name=""):
        self.name = name
        self.callbacks = []

    def callback(self, idx, arg):
        self.callbacks[idx](self, arg)

# First argument should be a ref to class
def callback(fcn, arg):
    fcn.name=arg

# Create a instance of class
a = MyClass("Blue")

# Lets add new member functions
a.callbacks.append(callback)
a.callbacks.append(callback)

print a.name
a.callback(0, "purple")
print a.name
a.callback(1, "cyan")
print a.name

答案 2 :(得分:1)

简而言之:在移植方法时,将其分配给类,而不是实例。

这是一个清晰的例子。

class A(object):
    """As trivial as a class can get."""
    def foo(self):
        return self.bar(1) + self.baz()

# Rework everything!

def new_bar(self, x):
    return 'I got %r' % x

def new_baz(self):
    return ' and I\'m okay!'

A.bar = new_bar
A.baz = new_baz

print A().foo()

现在将方法移植到实例

a = A()

# An instance attribute is a bound method;
# when we replace it with a function, we lose access to self.
a.bar = lambda x: x * 100

A.baz = lambda self: 42

assert a.foo() == 142

# We can do better, though.
from types import MethodType

a2 = A()
a2.foo = MethodType(lambda self: 'I know myself, my class is %s' % self.__class__.__name__, a2)
print a2.foo()

请注意,您不需要setattr来设置属性,甚至是未知属性。您可能还记得,setattr中也没有使用__init__