I am new to python and trying to update a variable, say x, in an imported module and then trying to use the updated variable x in other variable, say y, but y uses the old value of x instead of the new value. Please help provide some pointers to make it work!
My intention is to use a py file to list all global variable which I can use them in other py files. I could update a global variable and use it but not sure how to use an updated global variable in other variables.
Sample code:
a.py:
var1 = 0
var2 = var1 + 1
b.py:
import a
def update_var():
a.var1 = 10
print("Updated var1 is {}".format(a.var1))
print("var2 is {}".format(a.var2))
if __name__ == "__main__":
update_var()
Output:
Updated var1 is 10
var2 is 1
Expected Output:
Since i am updating var1 to 10, i am expecting that the updated value be used in var2
Updated var1 is 10
var2 is 11
Python doesn't work that way. When you import a module, the code in the module is executed. In your case, that means two variables are defined: a.var1 with value 0 and a.var2 with value 1. If you then modify a.var1, you won't affect a.var2, its value was defined when you imported the module and it won't change unless you explicitly alter it.
This is due to var2 being initialized only once whilst importing.
The way around this would be to write a getter or and update function.
A possible getter function would be:
a.py
var1 = 0
var2 = var1 + 1
def getVar2():
return var1 + 1
b.py:
import a
def update_var():
a.var1 = 10
print("Updated var1 is {}".format(a.var1))
print("var2 is {}".format(a.getVar2()))
if __name__ == "__main__":
update_var()
A possible update function would be:
a.py
var1 = 0
var2 = var1 + 1
def updateVar2():
var2 = var1+1
b.py:
import a
def update_var():
a.var1 = 10
a.updateVar2()
print("Updated var1 is {}".format(a.var1))
print("var2 is {}".format(a.var2()))
if __name__ == "__main__":
update_var()
Based on the inputs from #GPhilo and my personal experiences i came up with below working solutions, guess solution 2 is more pythonic.
Solution 1:
a.py:
class Globals:
def __init__(self, value):
self.var1 = value
self.var2 = self.var1 + 1
b.py:
from a import Globals
def update_var():
globals_instance = Globals(10)
print("Updated var1 is {}".format(globals_instance.var1))
print("var2 is {}".format(globals_instance.var2))
if __name__ == "__main__":
update_var()
Output:
Updated var1 is 10
var2 is 11
Solution 2:
Change implementation of a.py as below"
a.py:
class Globals:
def __init__(self, value):
self._var1 = value
self.var2 = self._var1 + 1
#property
def var1(self):
return self._var1
#var1.setter
def var1(self, value):
self._var1 = value
Related
How can i get the output from another script?
My first script to run:
from test2 import *
class Test():
def todo (self):
mult()
addx()
if __name__ == '__main__':
Test().todo()
My second script named (test2.py):
def mult():
x= 2 * 4
print(x)
return x
def addx():
sum = x + 2
print("sum",sum)
Error:
NameError: name 'x' is not defined
In the function addx() you haven't declared x. I believe you want x from mult. So you can do something like this
def addx():
x = mult()
sum = x + 2
print("sum",sum)
You should use the return value of mult, to pass it to your second function addx as a parameter.
def todo (self):
x = mult()
addx(x)
I advise you to read the Python doc section about function : https://docs.python.org/fr/3/tutorial/controlflow.html#defining-functions
In test2.py, you have not defined x
def addx():
sum = x + 2
print("sum",sum)
The problem above is that the computer doesn't know what x is. You could pass it as a parameter:
def addx(x):
sum = x + 2
print("sum", sum)
and change your code to:
from test2 import *
class Test():
def todo(self):
addx(x=mult()) # whatever number you want
if __name__ == '__main__':
Test().todo()
If this is my code:
x = 1
x = 2
x = 3
How can I “log” the things x has been and print them? If my explanation was dumb, then here’s what I expect:
>>> # Code to print the things x has been
1, 2, 3
>>>
How can I achieve this?
Since assignment overwrites the value of the object (in your example 'x'), it is not possible to do exactly what you want. However, you could create an object, of which the value can be changed and its history remembered. For example like this:
#!/usr/bin/env/python3
class ValueWithHistory():
def __init__(self):
self.history = []
self._value = None
#property
def value(self):
return self._value
#value.setter
def value(self, new_value):
self.history.append(new_value)
self._value = new_value
def get_history(self):
return self.history
def clear_history(self):
self.history.clear()
def main():
test = ValueWithHistory()
test.value = 1
print(test.value)
test.value = 2
print(test.value)
test.value = 3
print(test.value)
print(test.get_history())
if __name__ == '__main__':
main()
This prints:
1
2
3
[1, 2, 3]
Of course, you could also use a set instead of a list to only remember each unique value once, for example.
You can order a second thread to observe the string and print the changes:
from threading import Thread
def string_watcher():
global my_string
global log
temp = ''
while True:
if my_string != temp:
log.append(my_string)
temp = my_string
t = Thread(target=string_watcher, daemon=True)
t.start()
This checks weather the string „my_string“ was manipulated and appends it to the list „log“, if it has been changed. With this you should be able to perform
Print(log)
At any moment of the runtime
I have written the following code in Python 3.6.2:
user=0
def test():
global user
d = locals()
exec('user=1', globals(), d)
test()
print(user)
I want to use variable user (it is global) in exec and change its value to 1 and in print(user) print its value, but it is printing 0.
How can fix it?
You need to declare the variable global in the executed code:
>>> user = 0
>>> def test():
... exec('global user; user=1', globals())
...
>>> test()
>>> print(user)
1
I am trying to write a program with python functions. The variables used in one function will be needed in various other functions.
I have declared it as global in the first function, then used the returned value in the second function. However in the third function, I would like to use the updated value from the second, but I am only able to get the values from the first function.
def func():
global val, val2
val = 3
val2 = 4
return val, val2
def func1(val, val2):
val = val + 1
val2 = val2 + 1
return val, val2
def func2(val,val2):
val = val + 1
val2 = val2 + 1
print val, val2
func()
func1(val, val2)
func2(val, val2)
I would like to get 5,6 as the answer, but am getting 4,5.
Assign the return values of your functions to val and val2.
val, val2 = func()
val, val2 = func1(val, val2)
func2(val, val2)
If the variable is declared as a function argument, it's a local variable for this function. In Your case if You declare def func1(val,val2): then val,val2 will both be local in function func1. If You want to use global variables do it like that:
def func():
global val,val2
val=3
val2=4
return val,val2
def func1():
global val,val2
val=val+1
val2=val2+1
return val,val2
def func2():
global val,val2
val=val+1
val2=val2+1
print val,val2
func()
func1()
func2()
returns:
5 6
But I think that using global variables should be avoided if using them is not necessary (check Why are global variables evil?). Consider using return the right way like in pp_'s answer.
I want to mock a function that calls an external function with parameters.
I know how to mock a function, but I can't give parameters. I tried with #patch, side_effects, but no success.
def functionToTest(self, ip):
var1 = self.config.get(self.section, 'externalValue1')
var2 = self.config.get(self.section, 'externalValue2')
var3 = self.config.get(self.section, 'externalValue3')
if var1 == "xxx":
return False
if var2 == "yyy":
return False
[...]
In my test I can do this:
def test_functionToTest(self):
[...]
c.config = Mock()
c.config.get.return_value = 'xxx'
So both var1, var2 and var3 take "xxx" same value, but I don't know how to mock every single instruction and give var1, var2 and var3 values I want
(python version 2.7.3)
Use side_effect to queue up a series of return values.
c.config = Mock()
c.config.get.side_effect = ['xxx', 'yyy', 'zzz']
The first time c.config.get is called, it will return 'xxx'; the second time, 'yyy'; and the third time, 'zzz'. (If it is called a fourth time, it will raise a StopIteration error.)