This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 5 years ago.
I am currently writing my first script in python and have functions that are all similar, except for the fact that one number in each variables name changes.
For example like this:
def Function1():
global Var1
Var1 = A1
global Var2
Var2 = B1
def Function2():
global Var1
Var1 = A2
global Var2
Var2 = B2
The variables Ax, Bx and so on are read from a file. Then, if I click a tkinter-Button, one of these functions is activated and the global variables Var1 and Var2 are set to either A1 and B1 or A2 and B2 and so on...
Since this is just copy and pasting the functions and then manually changing the number in the variable name that is read from the file, I thought there has to be a way to make this easier. Something like this:
def Function1():
FUNCTIONNUMBER = 1
global Var1
Var1 = ("A" + FUNCTIONNUMBER)
global Var2
Var2 = ("B" + FUNCTIONNUMEBR)
In other words, something that makes it possible to set up a variable name from a constant part ("A") and a changing part ("1" or "2" or "3"...)
I´ve already searched for this question, but didn´t find anything that helps me with my specific case, since I don´t want to create variables out of nowhere or I don´t want to write all the variable names in a dictionary. I just want to make python think it reads a variable name that consists of different parts.
Thank you in advance!
I think what you're looking for is a list. let me show you and example
some_list = ["hey", "hows", "it", "going"]
print(some_list[0])
print(some_list[2])
This output would be:
hey
it
a list is just that, a list of numbers/strings/function/other lists, and you access them by specifying which position in the list you want (starting at 0)
Related
This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 8 months ago.
This post was edited and submitted for review 8 months ago and failed to reopen the post:
Original close reason(s) were not resolved
The problem:
I have a dictionary of keys and values:
param_dict = {
'VAR1' : 'abcd',
'VAR2' : (1, 1),
'VAR3' : 10.0
}
I want to write a function that takes in such a dictionary, and will set each key-value pair as a global variable.
What I have so far:
I have already figured out how to create global variables from my dictionary (as described in a number of answers to this older question). I run into problems only when trying to write my code (shown in the cell below) as a function.
# Set defined values as global variables
for k, v in param_dict.items():
exec(k + '=v')
You can see that each dictionary key is now the name of a global variable, and each dictionary value is the corresponding value:
print(VAR1) # Prints the value of the global variable VAR1
But I don't know how to accomplish the same thing with a function, since placing all my code within a function will result in the creation of local variables, not global variables.
def make_globals(param_dict):
# Set defined values as global variables
for k, v in param_dict.items():
exec(k + '=v')
make_globals(param_dict=param_dict)
print(VAR1) # Returns a NameError
I know you can set global variables from within a function using global (as shown here and here), but this method requires the name of the variable to be hard-coded into the function itself (at least as far as I can tell). This doesn't work for me since my global variable names can vary and I'm looping through multiple key-value pairs that I want to use as global variables. Is there a way around this?
You can do it this way:
def make_globals(param_dict):
# Set defined values as global variables
for k, v in param_dict.items():
vStr = f'"{v}"' if isinstance(v, str) else f'{v}'
exec(f'{k}={vStr}', globals())
param_dict = {
'VAR1' : 'abcd',
'VAR2' : (1, 1),
'VAR3' : 10.0
}
make_globals(param_dict=param_dict)
print(f'VAR1 is {VAR1}')
for k in param_dict:
print(f'{k} is in globals()') if k in globals() else print(f'{k} is not in globals()')
Output:
VAR1 is abcd
VAR1 is in globals()
VAR2 is in globals()
VAR3 is in globals()
One key point is to pass globals() as an argument to exec(). I also made some changes to the strings you were passing into exec().
UPDATE:
Here's what the first argument passed to exec() looks like:
VAR1="abcd"
VAR2=(1, 1)
VAR3=10.0
Supposing we have the code below:
var1="top"
var2=var1+"bottom"
We want to change var1 value if a condition is true:
if COND==True:
var1="changed"
Now I want to have var2 dynamically changed. With the code above, var2 will still have the value "topbottom".
How can I do that?
Thanks
You can elegantly achieve this with a callback proxy from ProxyTypes package:
>>> from peak.util.proxies import CallbackProxy
>>> var2 = CallbackProxy(lambda: var1+"bottom")
>>> var1 = "top"
>>> var2
'topbottom'
>>> var1 = "left"
>>> var2
'leftbottom'
Each time you access your var2, callback lambda will be executed and a dynamically generated value returned.
You can use string formatting to specify a placeholder in var2 where you want the updated value of var1 to be placed:
In [1653]: var2 = '{}bottom'
The {} brackets here specify a placeholder. Then call var2.format to insert var1 into var2 as and when needed.
In [1654]: var1 = 'top'
In [1655]: var2.format(var1)
Out[1655]: 'topbottom'
In [1656]: var1 = 'changed'
In [1657]: var2.format(var1)
Out[1657]: 'changedbottom'
There is no simple way to do this as string are immutable in python. There is no way var2 can be changed after var1+"bottom" evaluation. You either need to create a new string (not sure why do don't want to do this) or you need to write your own class and create your own objects that accept this behavior. If you want to do this, take a look at Observer Pattern
As others have said, since strings are immutable you must find a way to insert the dynamic value on the formation of the string.
I am a fan of the new 'fstrings' in Python- single line 'if' statement for flare:
cond = True
var1 = "changed" if cond is True else "top"
var2 = f"{var1} bottom"
print(var2)
This question already has answers here:
How do I create variable variables?
(17 answers)
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Closed 7 months ago.
I'd like to create a function that will modify an initialized global variable based on the argument passed to it, but I get a SyntaxError: name 'arg' is local and global. I have seen other methods to accomplish this, using globals() or creating a simple func inside myFunc to "trick" Python. Another approach would be to create if statements inside myFunc to explicitly assign the corresponding global variables, but that seems overly verbose.
Why does this occur, and what would be the most efficient/elegant/Pythonic way to accomplish this?
Given:
var1 = 1
var2 = 2
var3 = 3
def myFunc(arg):
global arg
arg = 10
myFunc(var1) # each of these should print to 10
myFunc(var2)
myFunc(var3)
You can use globals() to access the variables and assign new values from within myFunc()
var1 = 1
var2 = 2
def myFunc(varname):
globals()[varname] = 10
print(var1, var2)
myFunc("var1")
myFunc("var2")
print(var1, var2)
Will output:
1, 2
10, 10
In python a variable is a name for an object. When you call a function, and pass it an argument you're passing the object associated with the variable, not the name. So for example when you call wash(mydog), you're saying "wash the object known as mydog". Keep in mind, that the same object could have more than one name, for example spot = mydog = best_dog_ever = new_dog(). The function doesn't know which name was used to pass it the object, and even if it did, what if the name used was not the one in the global scope, you'd have to have some way of saying this function only takes global variables as arguments.
I hope that helps explain why you're getting a syntax error, but you can still accomplish pretty much the same thing at least two ways. The first is to simply assign the return value to the variable you're trying to change, for example:
var1 = 1
var2 = 2
def addone(a):
return a + 1
def main():
global var1, var2
var1 = addone(var1)
var2 = addone(var2)
print var1, var2
main()
print var1, var2
The second is to use a more object oriented approach, something like this:
class GlobalValue(object):
def __init__(self, value):
self.value = value
var1 = GlobalValue(1)
var2 = GlobalValue(2)
def addone(a):
a.value += 1
print var1.value, var2.value
addone(var1)
addone(var2)
print var1.value, var2.value
Or even better:
class GlobalValue(object):
def __init__(self, value):
self.value = value
def addone(self):
self.value += 1
var1 = GlobalValue(1)
var2 = GlobalValue(2)
print var1.value, var2.value
var1.addone()
var2.addone()
print var1.value, var2.value
Why does this occur
Because the global variable that you want to use has the same name as the parameter, arg. In Python, parameters are local variables, and a variable can only be local or global, not both.
It appears as though you expected to be able to use the contents of var to, somehow, specify which existing global variable to modify. It does not work like that. First off, variables don't contain other variables; they contain values. The name of a variable isn't a value. Again, parameters are local variables - and calling a function assigns to those variables. It assigns a value. (Keep in mind that you could just as easily call the function without a variable for the argument: myFunc(3). Should this cause 3 to become equal to 10 somehow?)
Second, even if you passed, for example, a string, you would have to do more work in order to access the corresponding global variable. It can be done, but please do not.
and what would be the most efficient/elegant/Pythonic way to accomplish this?
The Pythonic way is don't. If you want your function to communicate information out when it is called, return a value:
def myFunc():
return 10
var1 = myFunc()
var2 = myFunc()
var3 = myFunc()
The simplest way to fix the error is to just rename the global variable. However, this does not fix the apparent intent of the code:
var1 = 1
var2 = 2
var3 = 3
def myFunc(arg):
global g
g = 10
# var1, var2 and var3 will NOT CHANGE
# Instead, the new global variable g is created, and assigned a value of 10,
# three times in a row.
myFunc(var1)
myFunc(var2)
myFunc(var3)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the difference between list and list[:] in python?
I am quite new in python so I bumped into a situation where I was unable to find a response for the following question.
What does this means in python?
l[:] = process_list(l)
l is type list
Basically I have a global declared list that I want to modify it(override the old values with the new ones) based on the response of the process_list method. When I try like this:
l = process_list(l)
I get this: Unresolved reference 'l'
Can you please explain what is the difference and if the first approach that I am using currently is a good one?
In a function, an assignment to a name that could be a local variable creates a local variable by that name, even if it shadows a global:
a = None
def foo():
a = 5 # local 'a' shadows global 'a'
Slice assignment is modification, not assignment, so the name continues to refer to the global:
a = [1, 2, 3]
def foo():
a[:] = [5] # modifies global 'a'
The Unresolved reference happens because by creating a local variable shadowing the global, the global can no longer be seen. Another way to do what you want could be to use global:
a = None
def foo():
global a
a = 5 # rebinds global 'a'
list[:] = whatever will change the contents of the existing list
(as opposed to replacing it with list = whatever) ... by the way list is a terrible variable name ...
So I wrote this function from a book I am reading, and this is how it starts:
def cheese_and_crackers(cheese_count, boxes_of_crackers):
print "You have %d cheeses!" % cheese_count
print "You have %d boxes of crackers!" % boxes_of_crackers
print "Man that's enough for a party!"
print "Get a blanket.\n"
ok, makes sense. and then, this is when this function is run where I got a little confused and wanted to confirm something:
print "OR, we can use variables from our script:"
amount_of_cheese = 10
amount_of_crackers = 50
cheese_and_crackers(amount_of_cheese, amount_of_crackers)
the thing that confused me here is that the amount_of_cheese and amount_of_crackers is changing the variables (verbage? not sure if i am saying the right lingo) from cheese_count and boxes_of_crackers repectively from the first inital variable labels in the function.
so my question is, when you are using a different variable from the one that is used in the initial function you wrote, why would you change the name of the AFTER you wrote out the new variable names? how would the program know what the new variables are if it is shown after it?
i thought python reads programs top to bottom, or does it do it bottom to top?
does that make sense? i'm not sure how to explain it. thank you for any help. :)
(python 2.7)
I think you are just a bit confused on the naming rules for parameter passing.
Consider:
def foo(a, b):
print a
print b
and you can call foo as follows:
x = 1
y = 2
foo(x, y)
and you'll see:
1
2
The variable names of the arguments (a, b) in the function signature (1st line of function definition) do not have to agree with the actual variable names used when you invoke the function.
Think of it as this, when you call:
foo(x, y)
It's saying: "invoke the function foo; pass x in as a, pass y in as b". Furthermore, the arguments here are passed in as copies, so if you were to modify them inside the function, it won't change the values outside of the function, from where it was invoked. Consider the following:
def bar(a, b):
a = a + 1
b = b + 2
print a
x = 0
y = 0
bar(x, y)
print x
print y
and you'll see:
1
2
0
0
The script runs from top to bottom. The function executes when you call it, not when you define it.
I'd suggest trying to understand concepts like variables and function argument passing first.
def change(variable):
print variable
var1 = 1
change(var1)
In the above example, var1 is a variable in the main thread of execution.
When you call a function like change(), the scope changes. Variables you declared outside that function cease to exist so long as you're still in the function's scope. However, if you pass it an argument, such as var1, then you can use that value inside your function, by the name you give it in the function declaration: in this case, variable. But it is entirely separate from var! The value is the same, but it is a different variable!
Your question relates to function parameter transfer.
There are two types of parameter transfer into a function:
By value ------- value changed in function domain but not global domain
By reference ------- value changed in global domain
In python, non-atomic types are transferred by reference; atomic types (like string, integer) is transferred by value.
For example,
Case 1:
x = 20
def foo(x):
x+=10
foo()
print x // 20, rather than 30
Case 2:
d = {}
def foo(x): x['key']=20
foo(d)
print d // {'key': 20}