4

我想创建一个行为类似于 python 变量但在“变量”被更改/读取时调用一些回调函数的类。

换句话说,我希望能够按如下方式使用该类:

x=myClass(change_callback, read_callback)

将 x 定义为 myclass 的一个实例。构造函数(INIT)将 2 个函数作为参数:每次更改 x 时调用的函数,以及每次“读取”x 时调用的函数

以下声明:

x=1

change_callback(1)将“保存” 1 并触发可以执行任何操作的调用。

以下声明:

a=x

将检索存储的值并调用read_callback()这可能会更改存储的值并执行其他操作。

我希望它适用于任何类型,例如能够编写如下内容:

x=[1 2 3]这会触发change_callback([1 2 3])

x.append(4)会触发change_callback([1 2 3 4])(并且可能会触发之前的调用read_callback()

x={'a':1}会触发change_callback({'a':1})

print(x)当然会触发对 read_callback() 的调用...并返回最后存储的值进行打印。

这个想法是可以记录对变量的任何访问,或生成其他计算……毫无疑问。

我觉得这应该是可能的,但我真的不知道我的对象应该继承什么......如果我必须将我限制为一种类型,例如列表,有没有办法重新定义所有赋值运算符(包括“一次性”中的 append()...) 等方法,保持原始行为(基类方法)并添加回调...

还是有更合适的方法(模块...)来实现相同的目标...?

提前致谢,

4

4 回答 4

8

对象不知道它们何时被分配给变量。写作添加了一个x = a指向. a对象不会得到通知(尽管在 CPython 中,它的引用计数会增加)。

得到通知的部分是分配对象的容器。在全局分配的情况下,模块字典得到更新。在实例变量更新的情况下a.b = x,有一个虚线查找并存储到实例字典中。

您可以使这些容器在查找或存储时调用任意代码。Python 的属性为新型类提供了这种能力。execeval操作允许您指定一个自定义 dict,可以为常规分配提供此功能。在这两种情况下,您都可以完全控制分配时发生的事情。

摘要:查找和存储行为是通过分配的目标而不是被分配的对象来控制的。

示例

from collections import namedtuple

CallbackVar = namedtuple('CallbackVar', ['change_callback', 'read_callback'])

class CallbackDict(dict):
    'Variant of dict that does callbacks for instances of CallbackVar'
    def __getitem__(self, key):
        value = dict.__getitem__(self, key)
        if isinstance(value, CallbackVar):
            return value.read_callback(key)
    def __setitem__(self, key, value):
        try:
            realvalue = dict.__getitem__(self, key)
            if isinstance(realvalue, CallbackVar):
                return realvalue.change_callback(key, value)
        except KeyError:
            pass
        return dict.__setitem__(self, key, value)

stmts = '''
x = CallbackVar(setter, getter)     # Attach getter() and setter() to "x"
x = 1                               # Invoke the setter()
x                                   # Invoke the getter()
'''

def getter(key):
    print 'Getting', key
    return 42

def setter(key, value):
    print 'Setting', key, 'to', value

exec stmts in globals(), CallbackDict()
于 2012-03-24T17:53:47.097 回答
4

您可能想查看描述符: http: //docs.python.org/howto/descriptor.html

不过,这仅适用于对象属性,这对您来说可能就足够了。

于 2012-03-24T17:53:56.270 回答
2

您不能对操作符执行此=操作 - 因为根据定义,它旨在覆盖左侧,无论其当前内容是什么,都不会收到任何通知表明这种情况正在发生。(并且赋值运算符在 Python 中是不可覆盖的。)

但是,您可以做的是在您的类上使用.set().get()方法。它不会让你获得完全相同的“魔法”,但老实说,这可能是一件好事——它让你更清楚发生了什么。

于 2012-03-24T17:49:51.030 回答
1

变量是对 python 对象的引用。说“一个类的行为就像一个变量”是错误的。当你这样做时

x = [1, 2, 3]

该变量x将是对新列表对象的引用(重定向[1, 2, 3]) ,而不是您的旧对象被“更改”。它只是失去了一个参考。

做你想做的事。尝试调用您班级change_callback__init__方法。

read_callback被叫。做这样的事情

class A(object):
    def __init__(self): 
        self._x = 3
    @property
    def x():
        read_callback() # called!
        return self._x
    ....
a = A()
print a.x

如果这是你什么。

于 2012-03-24T18:07:59.680 回答