How to create recalculation of variables in Python

Suppose I have code:

a = 2 b = a + 2 a = 3 

The question is: how to save b update with every change in a ? For example, after the above code, I would like to get: print(b) as 5 , not 4 .

Of course, b can be a function of a through def , but, say, in IPython it is more convenient to have simple variables. Is there any way to do this? Maybe through SymPy or other libraries?

+4
source share
7 answers

You can make a lambda, which is basically a function ... The only thing you need to do is b() to get the value instead of just b

 >>> a = 2 >>> b = lambda: a + 2 >>> b() 4 >>> a = 3 >>> b() 5 
+7
source

Fair warning : this is a hack that is only suitable for experimentation and playback in the Python interpreter environment. Do not load untrusted entries in this code.

You can define b as an instance of the following class:

 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)) 

Instances of this object will automatically evaluate the expression when printed or echoed in the Python interpreter. Expressions only support references to global names.

Demo:

 >>> a = 5 >>> b = Expression('a + 5') >>> b 10 >>> a = 20 >>> b 25 
+4
source

If you want to use the sympy solution:

 >>> 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 

Or you can even create your own rating function:

 >>> 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 
+2
source

You cannot do this in the same way as Java or C. However, you can wrap a variable with your own custom class to achieve your goal.

Take a look at the following example:

 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 
+1
source

Looks like you want a 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(ca) # prints 2 print(cb) # prints 4 ca = 10 print(cb) # prints 12 

Take a look at the documentation on using property as a decorator to find out how to add setters, etc., if you want to. Since you did not specify how b installed, I just hardcoded it, but it would be trivial to make the custom part of b custom; sort of:

 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 
+1
source

Part of what you are saying is that you want the sounds to look like the way cells work in most spreadsheets, so I suggest you use something like this highly rated ActiveState Recipe . It is so short and simple, I will reproduce it here and apply to your trivial example:

 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 

Many comments on the recipe describe improvements, some significant ones, so I also suggest reading them.

+1
source

I got this idea after working with Qt. It uses an object property, not a variable:

 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 

But what if you want to know when o1.a changed? This is my first wish, but the implementation is complicated. Even if this probably answers another question, here is an example:

 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 
+1
source

Source: https://habr.com/ru/post/1495372/


All Articles