有两个对象(或简单变量),我希望它们能够被双向观察到'或者无论名称应该是什么。值应该像这样跟踪:
# just some variables
a = 5
b = 4
track(a,b)
a = 3
print(b) --> 3
b = 6
print(a) --> 6
实际上,这些应该是两个对象的属性或两个字典的值。或者 - 两个字典的值是不同类的两个对象的一部分。
更好/更糟的是,两个(不同的)类可以使用例如 __setitem __ / __ getitem__访问值并进行额外的计算,这应该在“兄弟”时触发。变化:
class A():
def __init__(self):
self.d = {'a':3}
def __setitem__(self, key, value):
self.d[key] = value
self.do_magic_computation(key, value)
class B():
def __init__(self):
self.d = {'b':3}
def __setitem__(self, key, value):
self.d[key] = value
self.do_another_computation(key, value)
a = A()
b = B()
track(a['a'], b['b'])
a['a'] = 5
print(b['b']) --> 5 (+ magic computation happened in a and b)
我的想法如下:做一个循环的观察者模式和一个跟踪器'将侦听 a 和 b 中的更改的对象。然后它会触发“兄弟”。
对某些魔法的任何想法' python方式来完成这个?
答案 0 :(得分:2)
如果您想要的只是能够以两种或更多种方式引用一个可变位置,而不是方便的语法糖用于相同的功能,那么您可以简单地使用list
来实现它:< / p>
a = b = [4]
a[0] = 5
print(b[0]) --> 5
显而易见,您可以对对象属性和字典值以及其他任何内容使用相同的方法。
可以肯定的是,如果你想要的是一个类似于你实际描述的真正通用track()
函数,那么在Python中这是不可能的,因为你不能“传递l值”开始。
答案 1 :(得分:1)
好吧,我很高兴地设计了一些永远不会用于生产的邪恶解决方案,只是为了它,当我意识到在python2.7中实际上不可能做到这一点。这个答案是分享我的失败和原因:
因此,要进行跟踪,我们需要在每个赋值上执行一些代码,以更新所有其他变量,以下行应该执行更新其他引用的代码(在您的示例中为b
):
a = 1
我的第一个想法是&#34;嗯,一个变量实际上存储在locals()或globals()字典中,所以让我们尝试使用其中一个&#34;的对象协议,问题是对象协议没有分配方法。
我的第二个想法是&#34; Hey a = 1
是字典赋值的语法糖&#34;,字典可以是globals()或locals(),其中语句等同于{{ 1}}或globals()['a'] = 1
,我们只需要locals()['a'] = 1
和globals().__setitem__
上的一些魔法来进行跟踪,但这两个词典实际上是围绕c代码的包装,这意味着我们不能覆盖{{} 1}}方法,这不是一个大问题,因为我们可以使用locals().__setitem__
并做一些戳,但后来我意识到永远不会调用__setitem__
。
有一个实现细节,作业将大致编译为:
ctypes
等等:
__setitem__
将编译为:
1 0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (a)
STORE_FAST和LOAD_FAST是跳过字典查找的cpython优化,而是使用b = c
指针数组。事实证明,4 12 LOAD_FAST 1 (b)
15 LOAD_FAST 2 (c)
19 STORE_FAST 1 (b)
与fastlocals
不同,并且没有简单的挂钩来调用代码。
答案 2 :(得分:0)
如何使用类字段来实现它:
class A(object):
fld = {}
def __init__(self):
self.d = {'a':3}
def __setitem__(self, key, value):
A.fld[key] = value
def __getitem__(self, key):
return A.fld[key]
a = A()
b = A()
a['a'] = 5
print a['a'] # prints 5
print b['a'] # prints 5
如果被跟踪的对象来自不同的类,则可以使用全局字典替换类变量:
fld = {}
class A(object):
def __init__(self):
self.d = {'a': 3}
def __setitem__(self, key, value):
fld[key] = value
def __getitem__(self, key):
return fld[key]
class B(object):
def __init__(self):
self.d = {'a': 3}
def __setitem__(self, key, value):
fld[key] = value
def __getitem__(self, key):
return fld[key]
a = A()
b = B()
a['a'] = 5
print a['a'] # prints 5
print b['a'] # prints 5