I want to have few global variables in my python code.
Then set their values with set function and want to get their values through get function.
For example:
a = None #global variable1
b= None #global variable2
def set(var, value):
var = value
def get(var):
return var
set(a, '1')
get(b, '2')
I want to have a generic get and set function which will do this for any global variable. How can I do this in python ? The code written here gives error.
If you're willing to pass the variable names as strings, you can do this using the globals() function. But even though you can, I don't think it's a good idea.
First, here's how you could do it:
def get_var(var_name):
return globals()[var_name]
def set_var(var_name, value):
globals()[var_name] = value
I'm not using the name set since that's a builtin type, which you probably don't want to shadow with something else.
You'd call it like:
set_var("foo", 1)
bar = get_var("foo")
print(foo, bar) # prints 1 1
So it works, but there's really no need for those functions. You can assign or fetch global variables using normal syntax instead. Just use foo = 1 instead of set_var("foo", 1) (if you're doing it in a function, put global foo first). Getting a global variable is as simple as naming it (like I do in print(foo)).
If you don't know the variable name ahead of time, you should probably be putting the name and value into a dictionary, rather than making them global variables. Variable names are for the programmer to use. They're not data!
Python is "call by value" not "call by reference". Meaning when you call "set(a, '1')", you are passing the value of "a" to the function "set". The variable "var" in "set" is a local variable to the function itself and will not effect your global variable "a". You need to give your setter and getter methods access to your global variables. You can do this by making them all part of a class object.
Related
This question already has answers here:
Using global variables in a function
(25 answers)
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 7 months ago.
I'm trying to add or subtract from a defined variable, but how can I overwrite the old value with the new one?
a = 15
def test():
a = a + 10
print(a)
test()
Error message:
Traceback (most recent call last):
File "test.py", line 7, in <module>
test()
File "test.py", line 4, in test
a = a +10
UnboundLocalError: local variable 'a' referenced before assignment
The error that you get when you try to run your code is:
UnboundLocalError: local variable 'a' referenced before assignment
… which, on the face of it, seems strange: after all, the first statement in the code above (a = 15) is an assignment. So, what's going on?
Actually, there are two distinct things happening, and neither of them are obvious unless you already know about them.
First of all, you actually have two different variables:
The a in your first line is a global variable (so called because it exists in the global scope, outside of any function definitions).
The a in the other lines is a local variable, meaning that it only exists inside your test() function.
These two variables are completely unrelated to each other, even though they have the same name.
A variable is local to a function if there's a statement assigning to it inside that function - for instance, your a = a +10 line.
Even so, the error still looks strange - after all, the very first thing you do inside test() is assign to a, so how can it be referenced beforehand?
The answer is that, in an assignment statement, Python evaluates everything on the right hand side of the = sign before assigning it to the name on the left hand side – so even though the assignment is written first in your code, a gets referenced first in that right hand side: a +10.
There are two ways you can get around this. The first is to tell Python that you really want the a inside test() to be the same a in the global scope:
def test():
global a
a = a + 10
print(a)
This will work, but it's a pretty bad way to write programs. Altering global variables inside functions gets hard to manage really quickly, because you usually have lots of functions, and none of them can ever be sure that another one isn't messing with the global variable in some way they aren't expecting.
A better way is to pass variables as arguments to functions, like this:
a = 15
def test(x):
x = x + 10
print(x)
test(a)
Notice that the name doesn't have to be the same - your new definition of test() just says that it accepts a value, and then does something with it. You can pass in anything you like – it could be a, or the number 7, or something else. In fact, your code will always be easier to understand if you try to avoid having variables with the same name in different scopes.
If you play with the code above, you'll notice something interesting:
>>> a = 15
>>> test(a)
25
>>> a
15
… a didn't change! That's because although you passed it into test() and it got assigned to x, it was then x that got changed, leaving the original a alone.
If you want to actually change a, you need to return your modified x from the function, and then reassign it back to a on the outside:
>>> a = 15
>>>
>>> def test(x):
... x = x + 10
... print(x)
... return x
...
>>> a = test(a)
25
>>> a
25
You're modifying a variable a created in the scope of the function test(). If you want the outer a to be modified, you could do:
a = 15
def test():
global a
a = a + 1
print(a)
test()
I would do it this way:
def test(a):
a = a +10
return a
print(test(15))
Note that in the version hereby proposed there are some things differing from yours.
First, what I wrote down would create a function that has, as an input, the value a (in this case set to 15 when we call the function -already defined in the last line-), then assigns to the object a the value a (which was 15) plus 10, then returns a (which has been modified and now is 25) and, finally, prints a out thanks to the last line of code:
print(test(15))
Note that what you did wasn't actually a pure function, so to speak. Usually we want functions to get an input value (or several) and return an input value (or several). In your case you had an input value that was actually empty and no output value (as you didn't use return). Besides, you tried to write this input a outside the function (which, when you called it by saying test(a) the value a was not loaded an gave you the error -i.e. in the eyes of the computer it was "empty").
Furthermore, I would encourage you to get used to writing return within the function and then using a print when you call it (just like I wrote in the last coding line: print(test(15))) instead of using it inside the function. It is better to use print only when you call the function and want to see what the function is actually doing.
At least, this is the way they showed me in basic programming lessons. This can be justified as follows: if you are using the return within the function, the function will give you a value that can be later used in other functions (i.e. the function returns something you can work with). Otherwise, you would only get a number displayed on screen with a print, but the computer could not further work with it.
P.S. You could do the same doing this:
def test(a):
a +=10
return a
print(test(15))
a = 15
def test():
global a
a = a + 10
print(a)
test()
If you want to change the values of local variables inside a function you need to use the global keyword.
The scope of the variable is local to the block unless defined explicitly using keyword global. There is another way to access the global variable local to a function using the globals function:
a = 15
def test():
a = globals()['a']
a += 10
print(a)
test()
The above example will print 25 while keeping the global value intact, i.e., 15.
The issue here is scope.
The error basically means you're using the variable a, but it doesn't exist yet. Why? The variable a has not been declared in the test() function. You need to "invite" global variables before using them.
There are several ways to include a variable in the scope of a function. One way is to use it as a parameter like this:
def test(number):
number = number + 10
print(number)
Then implement it as:
test(a)
Alternatively, you could also use the global keyword to show the function that a is a global variable. How? Like this:
def test():
global a
a = a + 10
print(a)
Using the global keyword just tells the test where to look for a.
With the first method, you can't modify the global variable a, because you made a copy of it and you're using the copy. In the second method, though, any changes you make in the function test() to a, will affect the global variable a.
# All the mumbo jumbo aside, here is an experiment
# to illustrate why this is something useful
# in the language of Python:
a = 15 # This could be read-only, should check docs
def test_1():
b = a + 10 # It is perfectly ok to use 'a'
print(b)
def test_2():
a = a + 10 # Refrain from attempting to change 'a'
print(a)
test_1() # No error
test_2() # UnboundLocalError: ...
Your error has nothing to do with it being already defined…
A variable is only valid inside its so-called scope: If you create a variable in a function it is only defined in this function.
def test():
x = 17
print(x) # Returns 17
test()
print(x) # Results in an error.
I have a program in python. part of the program is:
suggestengines = get_suggestengines(suggestengines)
sleeptimer = sleepcount * len(suggestengines)
seeds = get_seeds(dummydata=False)
For further programming I want to make a function of it:
def first_step():
suggestengines = get_suggestengines(suggestengines)
sleeptimer = sleepcount * len(suggestengines)
seeds = get_seeds(dummydata=False)
Now I get an error for "suggestengines" that I want to pass into get_suggestengines(). Also sleep timer and seeds get a marker, that I don't use them in the rest of the program. I googled it and got the answer: Us global. So I added global for everything
def first_step():
global suggestengines
global sleeptimer
global seeds
suggestengines = get_suggestengines(suggestengines) #which engines to run?
sleeptimer = sleepcount * len(suggestengines)
seeds = get_seeds(dummydata=False)
In further part of the program I have
for seed in tqdm(seeds, leave=True):
there the program gives me an error vor seeds in tqdm. If I change it to also make a def of it like:
def partTwo():
for seed in tqdm(seeds, leave=True):
Then I don't get an error anymore although I didn't used global. Can someone explain me why and if I need to use global in part 2 also?
The statement
global <identifier>
tells python that <identifier> should refer to a global when used in assignments. This is necessary in functions that change globals because Python has no syntactical difference between declaring a variable and assigning to an existing variable. The default in python is to have assignments in functions create new variables, rather than change global state.
When you just read from a variable there is no syntactic ambiguity, so Python will just use whatever variable it finds (i.e. global if there is no local one).
Example:
a = 1
def foo():
a = 2 # this will create a new, local variable a
def bar():
global a # "when I refer to a, I mean the global one"
a = 2 # this will change the global variable a
If no global with the specified name exists, the global statement itself will not create a new global variable, but any following assignment will. E.g. given the following:
def x():
global c
def y():
global c
c = 1
def z()
print c
x(); z() would be an error(global name 'c' is not defined), while y(); z() would print 1.
seeds hasn't been initialized yet by the time the for loop is hit, since its initialization is part of a def that hasn't been called yet. If you put the for loop inside a def then it will be called in the order you call the functions, so the interpreter won't complain until you actually use it.
The only thing to keep in mind here is this: use variables after they have been initialized.
I'm wanting to replace keywords with values from an associated dictionary.
file1.py
import file2
file2.replacefunction('Some text','a_unique_key', string_variable1)
file2.replacefunction('Other text','another_unique_key', string_variable2)
file2.replacefunction('More text','unique_key_3', string_variable2)
stringvariable1, used in the first function call, is a local variable in file1.py and therefore is accessible as a parameter in the function. It is intentionally a different variable than the one later used in that parameter position.
file2.py
import re
keywords = {
"a_unique_key":"<b>Some text</b>",
"another_unique_key":"<b>Other text</b>",
"unique_key_3":"<b>More text</b>",
}
def replacefunction(str_to_replace, replacement_key, dynamic_source):
string_variable2 = re.sub(str_to_replace, keywords[replacement_key], dynamic_source)
return string_variable2 <-- this variable needs to be accessible
The replacement values in the keywords dictionary are more complicated than shown above, and just demonstrated like this for brevity.
The problem occurs at the second call to replacefunction in file1.py - it cannot access stringvariable2 which is the result of the first function that is run.
I have seen that the way to access a variable produced in a function outside of that function is to do something like:
def helloworld()
a = 5
return a
mynewvariable = helloworld()
print mynewvariable
5 <-- is printed
But this approach won't work in this situation because the function needs to work on a string that is updated after each function call ie:
do this to string 2 # changes occur to string 2
do this to string 2 # changes occur to string 2
do this to string 2 # changes occur to string 2
I can achieve the required functionality without a function but was just trying to minimise code.
Is there any way to access a variable from outside a function, explicitly as a variable and not via assignment to a function?
Don't confuse variables with values. The name string_variable2 references a value, and you just return that from your function.
Where you call the function, you assign the returned value to a local variable, and use that reference to pass it into the next function call:
string_variable2 = file2.replacefunction('Some text','a_unique_key', string_variable1)
string_variable2 = file2.replacefunction('Other text','another_unique_key', string_variable2)
file2.replacefunction('More text','unique_key_3', string_variable2)
Here the replacefunction returns something, that is stored in string_variable2, and then passed to the second call. The return value of the second function call is again stored (using the same name here), and passed to the third call. And so on.
Ok, I started coding this:
lastentry = 'first'
campdata = {'a1'=0,
'b2'=0}
class Someclass:
def on_window1_destroy(self, widget, data=None):
print campdata
def func1(self)
lastentry = 'b2'
def func2(self)
lastentry = 'a1'
def func2(self)
campdata[lastcall] +=1
But then I found out that python strings (and integers) were immutable...
So how do I get around ths?
I guess your problem is that you want to change the value of the global variable lastentry by calling func1 or func2, which doesn't work. The reason it does not work is because the variable is in the global scope, and assigning to the same name inside of a function just creates a local variable with the same name as the global one. To assign to a global variable, you need to declare it as such:
lastentry = "something"
def func1():
global lastentry #tell python to treat references to lastentry as global
lastentry = "somethingelse"
Note that you don't need to do this if all you are doing with the global value is reading it like in your third function. But if you assign to a variable, it is treated as local to its scope - which is normally the surrounding function - if you don't explicitly declare it global (or nonlocal in python3).
Global variables should only be used when neccessary as they add complexity to the code. In your case you can probably refactor your code to use an instance variable or class variable for lastentry instead of a global one.
Like others have said, there doesn't seem to be any attempt to modify a string in your code, so that's hardly the problem.
That said, lastcall looks random, should it perhaps be lastentry?
I don't see any problem with your code (except for some details). String immutability does not seem to be a problem, here.
You may want to write, instead of the code in your question:
campdata = {'a1': 0, # Not "= 0"
'b2': 0}
and
campdata[lastentry] +=1 # not "lastcall"
Also, as l4mpi mentioned, you need a global lastentry in the methods where it is modified.
Another point: relying on global variables is quite unusual. If at all possible, it would be best to use instance attributes (self.campdata, self.lastentry).
I'd like to do something like this, but I get a SyntaxWarning and it doesn't work as expected
RAWR = "hi"
def test(bool):
if bool:
RAWR = "hello" # make RAWR a new variable, don't reference global in this function
else:
global RAWR
RAWR = "rawr" # reference global variable in this function
print RAWR # if bool, use local, else use global (and modify global)
How do I get this to work? Passing in True or False modifies the global variable.
You cannot. Within a scope, a specific name refers either to a local variable, or to a non-local (e.g. global, or from an outer function) variable. Not both. The global RAWR line makes RAWR a global for the entire scope (that's why you get a warning, it doesn't do what you think it does), just like assignment to a variable makes it local for the entire scope. Edit: Thanks to veredesmarald, we now know it is in fact a syntax error in Python 2. This half of my answer only applies to Python 3 apparently.
You should just use a differently-named local variable, and in the branch where you want to "promote" it to a global, set the global and the local variable. (Or just don't use globals at all.)
The only easy way you can go would be
RAWR = "hi"
def test(newone):
if newone:
lR = "hello" # make RAWR a new variable, don't reference global in this function
else:
global RAWR
lR = RAWR # reference global variable in this function
print lR # if bool, use local, else use global (and modify global)
# modify lR and then
if not newone:
RAWR = lR
Another way, however, could be to abuse the concept of classes and objects to your purposes.
class store_RAWR(object):
RAWR = "hi"
def __init__(self, new): self.RAWR = new
def test(newone):
if newone:
myR = store_RAWR("hello") # get a (temporary) object with a different string
else:
myR = store_RAWR # set the class, which is global.
# now modify myR.RAWR as you need
But this requires other program parts which use the global name to be changed as well.