Change global variable across class in python - python

I am trying to make a change to a global variable across classes. Here is my code:
file main.py
import class2
class first:
def changeA(self):
global a
print a
a += 2
print a
test0 = first()
test1 = class2.second()
test2 = first()
test3 = class2.second()
test0.changeA()
test1.changeA()
test2.changeA()
test3.changeA()
file class2.py
a = 1
class second:
def changeA(self):
global a
print a
a += 1
print a
But it returns an error: global name 'a' is not defined. Is there any proper way to access and change a global variable across files in python? Thanks in advance

Global variables don't exist in python.
The global statement is really a misnomed statement. What it means is that the variable is a module's variable. There is no such a thing as a global namespace in python.
If you want to modify a variable from multiple modules you must set it as an attribute:
import module
module.variable = value
Doing a simple assignment will simply create or modify a module's variable. The code
from module import variable
variable = value
simply shadows the value of variable imported from module creating a new binding with that identifier but module's variable value will not be changed.
In summary: no there is no way to achieve exactly what you want (although what you want would be a bad practice anyway, and you should try to use a different solution).

global variables are evil: avoid them!
It is much better to use a 'static' (in C++ terms) member variable, such as:
from class2 import second
class first:
def changeA(self):
print second.a
second.a += 2
print second.a
And:
class second:
a = 1
def changeA(self):
print second.a
second.a += 2
print second.a

Related

capture change of global variable value in python

How do i detect or capture change of value of a global variable in python
variable = 10
print(variable)
variable = 20
# Detect changes to the value using a signal to trigger a function
UPDATE
AST docs - GOOD INTRO
https://greentreesnakes.readthedocs.io/en/latest/
How about instrument the bytecode to add a print statement before each statement that stores to the global variable. Here is an example:
from bytecode import *
def instr_monitor_var(func, varname):
print_bc = [Instr('LOAD_GLOBAL', 'print'), Instr('LOAD_GLOBAL', varname),
Instr('CALL_FUNCTION', 1), Instr('POP_TOP')]
bytecodes = Bytecode.from_code(func.__code__)
for i in reversed(range(len(bytecodes))):
if bytecodes[i].name=='STORE_GLOBAL' and bytecodes[i].arg==varname:
bytecodes[i:i]=print_bc
func.__code__=bytecodes.to_code()
def test():
global a
a = 1
instr_monitor_var(test, 'a')
test()
instr_monitor_var can instrument a function test so the global variable a will be printed out when its value is changed. Let me know if this works. Thanks!
To my knowledge, it is not possible to generically capture the assignment of a global symbol in Python (At least in CPython where globals are stored in a dict in the module object, both are C types that cannot be monkey patched).
Here's a simple workaround that's a bit of a compromise. Use a wrapper object to store your monitored variables, and define __setattr__ to do whatever you want to do before (or after) setting an attribute.
class CaptureOnSetAttribute:
def __setattr__(self, attr, value):
# our hook to do something
print(f'set value of {attr} to {value}')
# actually set the attribute the normal way after
super().__setattr__(attr, value)
wrapper_object = CaptureOnSetAttribute()
The compromise of course is that now instead of writing something like:
monitored_global = value
You must now write:
wrapper_object.monitored_attribute = value

How do you make a string converted to a variable name instantiated inside of a function global?

Sorry for that confusing title, in my function my parameter is the name I want I want to set as a global variable name. I can do this outside of a function, and I can instantiate a global variable without a string as its name, and I haven't found any other articles with a solution to both problems at the same time.
def myFunc(varName):
temp = varName
# global vars()[temp] <== This line produces the error
vars()[temp] = 5 # varName becomes a local variable
You can use the globals function to achieve this:
def set_global_var(name, value):
globals()[name] = value
if __name__ == '__main__':
set_global_var('foo', 3)
print(foo)
Note that this is most of the case not a good idea. You might want to use a global dict object instead and simply assign new keys to it.
Using global, like so (notice that some_text is unknown before the call to fun1):
def fun1():
global some_text
some_text = "1234"
def fun2():
print(some_text)
fun1()
fun2()
This produces 1234 as one would expect, see a demo on ideone.com.
So, in your case just go for
def myFunc(varName):
global TEMP
TEMP = varName
Question remains: why would you want to do that? Don't clutter your global namespace with variables only a class/function needs.

Python: How to make variables consistent throughout different functions?

I'm still starting out how to program in Python, and I'm just wondering how to make a variable consistent throughout different functions. For example, a function that I've made modified a variable. Then, I've used that variable again in another function. How can I make the modified variable appear in the 2nd function? When I try it, the 2nd function uses the original value of the variable. How can you make it use the modified value? Do I need to use global variables for this?
Also, is the input() function recommended to be used inside functions? are there any side effects of using it inside them?
The variables need to be shared by a scope that is common to both functions, but this need not necessarily be a global scope. You could, for instance, put them in a class:
class MyClass:
def __init__(self):
self.x = 10
def inc(self):
self.x += 1
def dec(self):
self.x -= 1
mc = MyClass()
print mc.x # 10
mc.inc()
print mc.x # 11
mc.dec()
print mc.x # 10
What scope exactly the variable should exist in depends on what you're trying to do, which isn't clear from your question.
Use global variabale to access variable throughout code.
Demo:
>>> a = 10
>>> def test():
... global a
... a = a + 2
...
>>> print a
10
>>> test()
>>> print a
12
>>>
In class, use class variable which is access to all instance of that class. OR use instance variable which is access to Only respective instance of the class.
You can use return in the function.
x = 3
def change1():
x = 5
return x
x = change1()
def change2():
print(x)
change1()
change2()
You can use the global keyword at the top of the function to let python know that you are trying to modify the variable in global score. Alternatively, you could use OOP and classes to maintain an instance variable throughout class functions.
x = 5
def modify():
global x
x = 3
modify()

How to access a variable from a function in an imported file

So I have a file, let's name it main.py
In it, I have imported an external file, which we will call ext.py
Now let's say that these are the contents of ext.py:
def how():
tangerine = 1
And let's say these are the contents of main.py:
import ext
print #Not sure what or how
What I want to know is what to do to print out the tangerine variable via the main file.
Something like this: print ext.how().tangerine?
If I type in ext.tangerine it doesn't work as the tangerine is defined only in the how() function.
Please help as I really need it!
An alternative to using a global - return the value of tangerine from the function-:
def how():
tangerine = 1
return tangerine
in main.py-:
import ext
print ext.how()
You should probably use a class.
def how():
tangerine = 1
will always have the value 1. If you make it accessible globally as mentioned by the other posters, the variable will be accessible in the global namespace, which means every time you modify the variable outside the method, the functionality of your function may suffer, because it's dependend on a 'global state'. Most likely unwanted and bad things may happen.
Using classes/objects isn't difficult:
class Know(object):
def __init__(self, t):
self.tangerine = t
def how(self):
self.tangerine += 1
iknow = Know(0)
iknow.how()
youknow.Know(9)
youknow.how()
print youknow.tangerine
>>> 10
print iknow.tangerine
>>> 1

Class assigning index to object using static class variable

I have a class which represents an object to be kept in a set. I would like the class itself to remember how many it has created so that when you call SetObject() and __init__() a new object is created, which receives a unique index. Maybe something like this
class SetObject(object):
# static class variable
object_counter = 0
def __init__(self, params):
self.params=params
self.index = self.get_index()
def get_index(self):
object_counter += 1
return object_counter-1
a = SetObject(paramsa)
b = SetObject(paramsb)
print a.index
print b.index
would produce
0
1
or something like this. Currently it seems that this approach gives a "variable referenced before assignment" error.
You need to write:
def get_index(self):
SetObject.object_counter += 1
return SetObject.object_counter-1
otherwise it would only work if object_counter was a global variable.
You need to use a reference to the class to refer to it's variables; you could perhaps use a class method (with the #classmethod decorator), but there is really no need to.
Better use itertools.count() to get a fool-proof 'static' counter; no need to reassign back to the class attribute then:
import itertools
class SetObject(object):
object_counter = itertools.count().next
def __init__(self, params):
self.params=params
self.index = self.object_counter()
(code above assumes Python 2; on Python 3 iterables do not have a .next method and you'd need to use functools.partial(next, itertools.count()) instead).
Because the counter is an iterator, we don't need to assign to SetObject.object_counter at all. Subclasses can provide their own counter as needed, or re-use the parent class counter.
The line
object_counter += 1
translates to
object_counter = object_counter + 1
When you assign to a variable inside a scope (e.g. inside a function), Python assumes you wanted to create a new local variable. So it marks object_counter as being local, which means that when you try to get its value (to add one) you get a "not defined" error.
To fix it, tell Python where to look up object_counter. In general you can use the global or nonlocal keywords for this, but in your case you just want to look it up on the class:
self.__class__.object_counter += 1

Categories