使两个变量在python中相互跟踪

时间:2015-03-23 21:24:47

标签: python

有两个对象(或简单变量),我希望它们能够被双向观察到'或者无论名称应该是什么。值应该像这样跟踪:

# 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方式来完成这个?

3 个答案:

答案 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'] = 1globals().__setitem__上的一些魔法来进行跟踪,但这两个词典实际上是围绕c代码的包装,这意味着我们不能覆盖{{} 1}}方法,这不是一个大问题,因为我们可以使用locals().__setitem__并做一些戳,但后来我意识到永远不会调用__setitem__

有一个实现细节,作业将大致编译为:

ctypes

等等:

__setitem__

将编译为:

1           0 LOAD_CONST               1 (1)
            3 STORE_FAST               0 (a)

STORE_FASTLOAD_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