我想创建一个行为python变量的类,但在更改/读取“变量”时调用一些回调函数。
换句话说,我希望能够按如下方式使用该课程:
x=myClass(change_callback, read_callback)
将x定义为myclass的一个实例。构造函数( INIT )将2个函数作为参数:每次更改x时调用的函数,以及每次x“读取”时调用的函数
以下声明:
x=1
将“保存”1并触发对change_callback(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()...)等方法,保持原始行为(基类方法)并添加回调...
还是有更合适的方式(模块......)来实现相同的目标......?
提前致谢,
答案 0 :(得分:8)
对象不知道何时将它们分配给变量。写x = a
添加指向 a 的词条(或本地条目)。 a 对象不会得到通知(但是,在CPython中,它的引用计数会增加)。
获得通知的部分是分配对象的容器。在全局赋值的情况下,模块字典会更新。在像a.b = x
这样的实例变量更新的情况下,有一个虚线查找并存储到实例字典中。
您可以使这些容器在查找或存储上调用任意代码。 Python的 property 为新式类提供了这种功能。通过 exec 和 eval 操作,您可以指定可以为常规分配提供此功能的自定义字典。在这两种情况下,您都可以完全控制分配时发生的事情。
摘要:查找和存储行为可通过分配的目标进行控制,而不是分配对象。
示例强>:
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()
答案 1 :(得分:4)
您可能希望查看描述符:http://docs.python.org/howto/descriptor.html
这只适用于对象属性,这对您来说已经足够了。
答案 2 :(得分:2)
你无法使用=
运算符执行此操作 - 因为根据定义,它旨在覆盖左侧,无论当前内容是什么,都不会收到任何通知。 (并且赋值运算符在Python中无法覆盖。)
但是,您可以在课堂上使用.set()
和.get()
方法。它不会给你带来相同的“魔力”,但老实说,这可能是一件好事 - 它会让你更清楚发生了什么。
答案 3 :(得分:1)
Variable是对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
如果这就是你的意思。