假设我有代码:
a = 2
b = a + 2
a = 3
问题是:如何在b
的每次更改中更新a
?例如,在上述代码之后我想得到:print(b)
为5
,而不是4
。
当然,b
可以是a
通过def
的函数,但是,在IPython中,拥有简单变量会更舒服。有办法吗?也许通过SymPy
或其他图书馆?
答案 0 :(得分:8)
你可以做一个lambda,它基本上是一个函数......唯一的问题是你需要b()
来获取值而不仅仅是b
>>> a = 2
>>> b = lambda: a + 2
>>> b()
4
>>> a = 3
>>> b()
5
答案 1 :(得分:4)
公平警告:这是一个只适合在Python解释器环境中进行实验和游戏的黑客。请勿将不受信任的输入提供给此代码。
您可以将b
定义为以下类的实例:
class Expression(object):
def __init__(self, expression):
self.expression = expression
def __repr__(self):
return repr(eval(self.expression))
def __str__(self):
return str(eval(self.expression))
此对象的实例将在Python解释器中打印或回显时自动评估表达式。表达式仅支持对全局名称的引用。
演示:
>>> a = 5
>>> b = Expression('a + 5')
>>> b
10
>>> a = 20
>>> b
25
答案 2 :(得分:2)
如果你想要一个症状解决方案,你可以这样做:
>>> from sympy import Symbol
>>> a = Symbol('a')
>>> b = Symbol('b')
>>> c = (a + 3) * b
>>> c
b*(a + 3)
>>> c.subs({'a': 3, 'b': 4})
24
或者您甚至可以创建自己的评估功能:
>>> def e(exp):
vars = globals()
data = {}
for atom in exp.atoms():
if atom.is_Symbol:
if atom.name in vars:
data[atom.name] = vars[atom.name]
return exp.subs(data)
>>> a = 44
>>> b = 33
>>> e(c)
>>> 1551
>>> a = 1
>>> e(c)
>>> 132
答案 3 :(得分:1)
你不能像Java或C那样做。 但是,您可以使用自己的自定义类包装变量,以实现目标。
请看以下示例:
class ReferenceVariable:
def __init__(self, value):
self.value = value
def get(self):
return self.value
def set(self, val):
self.value = val
a = ReferenceVariable(3)
b = a
a.set(a.get()+4)
print(b.get()) // Prints 7
答案 4 :(得分:1)
看起来你想要property
。
class MyClazz(object):
def __init__(self, a):
self.a = a
@property
def b(self):
return self.a + 2
if __name__ == '__main__':
c = MyClazz(2)
print(c.a) # prints 2
print(c.b) # prints 4
c.a = 10
print(c.b) # prints 12
请查看使用property
作为装饰器的文档,详细了解如何添加setter等等。由于您未指定b
的设置方式,因此我对其进行了硬编码,但将b
特定部分定制为可行也是微不足道的;类似的东西:
class MyClazz(object):
def __init__(self, a, b_part=2):
self.a = a
self._b = b_part
@property
def b(self):
return self.a + self._b
答案 5 :(得分:1)
您所说的部分内容听起来很像大多数电子表格程序中的单元格,因此我建议您使用this highly rated ActiveState recipe中的内容。它简短而简单,我会在这里重现它并将它应用到你的小例子中:
class SpreadSheet(object):
_cells = {}
tools = {}
def __setitem__(self, key, formula):
self._cells[key] = formula
def getformula(self, key):
return self._cells[key]
def __getitem__(self, key ):
return eval(self._cells[key], SpreadSheet.tools, self)
from math import sin, cos, pi, sqrt
SpreadSheet.tools.update(sin=sin, cos=cos, pi=pi, sqrt=sqrt, len=len)
ss = SpreadSheet()
ss['a'] = '2'
ss['b'] = 'a + 2'
print ss['b'] # 4
ss['a'] = '3'
print ss['b'] # 5
许多食谱的评论都描述了改进,有些是重要的,所以我也建议阅读它们。
答案 6 :(得分:1)
我和Qt合作后得到了这个想法。它使用object属性,而不是变量:
from types import FunctionType
class MyObject:
def __init__(self,name):
self.name= name
self._a_f=None
self._a=None
@property
def a(self):
if self._a_f is not None:
self._a= self._a_f()
return self._a
@a.setter
def a(self,v):
if type(v) is FunctionType:
self._a_f=v
else:
self._a_f=None
self._a=v
o1,o2,o3=map(MyObject,'abc')
o1.a = lambda: o2.a + o3.a
o2.a = lambda: o3.a * 2
o3.a = 10
print( o1.a ) #print 30
o2.a = o1.a + o3.a #this will unbind o3.a from o2.a, setting it to 40
print( o1.a ) #print 50
但是,如果您想知道o1.a
何时更改,该怎么办?这就是我的第一个愿望,但实施很难。即使它可能回答其他问题,这里有一些例子:
class MyObject(metaclass=HaveBindableProperties):
a= BindableProperty()
someOther= BindableProperty()
o1,o2,o3=map(MyObject,'abc')
o1.a = lambda: o2.a + o3.a
o2.a = lambda: o3.a * 2
@o1.subscribe_a
def printa():
print( o1.a )
o3.a = 1 #prints 3
printa.unsubscribe() #to remove subscribtion