Access variables through their name as string in Python [duplicate] - python

This question already has answers here:
How can I select a variable by (string) name?
(5 answers)
Closed 4 years ago.
I would like to run a function with a list parameter :
param = ['a', 'b', 'c']
myFunction(param)
But a, b and c must be dynamic so I would like to remove the quotes to get this :
param = [a, b, c]
myFunction(param)
How can I do that ?
PS : I tried the solutions of this question but it didn't work Removing quotation marks from list items

If I understood correctly, you want to actually call myFunction with parameters a, b and c (assuming these are actually being defined earlier).
One way of doing this is:
a, b, c = 1, 2, 3
param = ['a', 'b', 'c']
def myFunction(x, y, z):
return x + y + z
myFunction(*[globals()[s] for s in param])
# returns: 6
EDIT:
As people have suggested, a safe way of doing this would be through globals() (or locals() using a slightly different construct). Otherwise, you could use eval() which is more powerful, but also potentially less safe.

'str''s cannot be converted to variable names, however if you do have th variables and your goal is to pass each variable to a function this is possible
def addition(x):
return x + 1
a = 1 b = 2 c = 3
param = [a, b, c]
print([addition(i) for i in param])
# [2, 3, 4]
The entire list could be passed as well like so
def addition(x):
return sum(x)
a = 1
b = 2
c = 3
param = [a, b, c]
print(addition(param))
# 6

Related

Python: How to add an integer value to each variable in a list?

I have 4 variables that each have an integer value:
a = 1
b = 2
c = 3
d = 4
I then have a list of the 4 variables:
list = [a, b, c, d]
How can I increment the value of all four variables in the list at once?
This is what I've tried so far:
for i in range(len(list)):
list[i] += 1
print(list)
print(a)
print(b)
print(c)
print(d)
And the list changed, but not the variables:
[2, 3, 4, 5]
1
2
3
4
How can I use the list to change the variables' values?
You need to create new a, b, c, and d variables that refer to the new value because list doesn't point to the old ones.
l = [a, b, c, d]
[a, b, c, d] = [x + 1 for x in l]
output:
> print(a, b, c, d)
2 3 4 5
How can I use the list to change the variables' values?
You can't, Python does not have general-purpose "dependent values". The stuff that's in the list are copies of the variables (but not the variable's values, those are different). Meaning there is essentially no relation between the two.
In order to relate the two, you'd need an indirection of some sort e.g. make both variable and list store some sort of reference, like an intermediate list.
Python actually has special-purpose references, usually via proxy objects. For instance locals() and globals() represent the corresponding scopes and give read/write access to their variables:
>>> a = 1
>>> globals()['a'] = 2
>>> a
2

Why can't I use multiple *vars in tuple unpacking on the left-hand side of an assignment?

I am trying to make sense of starred expressions in python. When I use it in python functions, it allows to call functions with different number of arguments:
def my_sum(*args):
results = 0
for x in args:
results += x
return results
print(my_sum(1,2,3))
>>6
print(my_sum(1,2,3,4,5,6,7))]
>>28
However when I use it in an assignment, it works like this:
a, b, *c, d = [1,2,3,4,5,6,7,8,9,10]
print(a,b,c,d)
>>1 2 [3, 4, 5, 6, 7, 8, 9] 10
*a, b, *c, d = [1,2,3,4,5,6,7,8,9,10]
print(a,b,c,d)
*a, b, *c, d = [1,2,3,4,5,6,7,8,9,10]
^
SyntaxError: multiple starred expressions in assignment
Can someone explain to me what is happening behind this assignment that doesn't allow multiple starred expressions?
The language doesn't allow this because it would be ambiguous, and allowing ambiguities is contrary to the Zen of Python:
In the face of ambiguity, refuse the temptation to guess.
Let's say you run:
*a, b, *c, d = [1,2,3,4,5,6,7,8,9,10]
One way to interpret that would be:
a = [1,2,3,4,5,6,7]
b = 8
c = [9]
d = 10
Another would be:
a = [1]
b = 2
c = [3,4,5,6,7,8,9]
d = 10
Yet another would be:
a = []
b = 1
c = [2,3,4,5,6,7,8,9]
d = 10
Python refuses to guess: It simply declares the code invalid.

using exec() to define new variables with names derived from the existing variable names [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 2 years ago.
I have a DataFrame (call it df) object with columns named A, B, and C where C is a binary variable. I am trying to create new variables A_1, A_0, B_1, and B_0 in a loop. These variables are created according to the value of C. For example A_0 is the portion of my original column A where the corresponding value of C is 0.
The following code does what I need:
variables=list('A', 'B')
for v in variables:
exec(f'{v}_0, {v}_1 = df.groupby("C")["{v}"]') #this returns a tuple
exec(f'{v}_0, {v}_1 = {v}_0[1], {v}_1[1]') #this returns what i need
It's clumsy, and, as far as I know, exec() is a bad practice. Is there a better way do this?
Just use a dict.
data = {}
for v in ["A", "B"]:
a, b = df.groupby("C")[v]
data[v] = (a[1], b[1])
EDIT: as discussed in the comments, to create keys V_0 and V_1,
data = {}
for v in ["A", "B"]:
a, b = df.groupby("C")[v]
data[f"{v}_0"] = a[1]
data[f"{v}_1"] = b[1]

How to store many inputs from a user in a set [duplicate]

This question already has answers here:
How do I call a function twice or more times consecutively?
(9 answers)
Closed 3 years ago.
My aim is to have many inputs from a user stored in a disordered manner. So, I decided to use a set. The code I have so far is:
a = input()
b = input()
c = input()
d = input()
all = a, b, c, d
print(set(all))
However, I do not want to repeat input() several times like above. Is there a way to achieve this?
If all you want is a set you do not need a, b, c, d.
all = set() #or all = {*(),}
for _ in range(4):
all.add(input())
print(all)
Or,
all = {input() for _ in range(4)}
This is considering you take the inputs in new line. Otherwise, if the input are comma-separated for example:
all = set(input().split(','))
print(all)
or
all = {*input().split(',')}
print(all)
In case you need both a, b, c, d and all the inputs, you could do:
>>> all = a, b, c, d = {*input().split(',')}
# example
>>> all = a, b, c, d = {1, 2, 3, 4}
>>> all
{1, 2, 3, 4}
>>> a
1
>>> b
2
As pointed out by #Tomerikoo all(iterable) is a built-in function avoid naming your variables same as python builints or keywords.
Another point, if in case you have already done so, in order to get the default behavior of all, you could do:
>>> import builtins
>>> all = builtins.all
# Or, more conveniently, as pointed out by #Martijn Pieters
>>> del all
* is used for iterable unpacking
_ is used for don't care or throwaway or anonymous variable,
as we do not need the variable in the loop. More on this
here.
{*()} is just a fancy way of creating empty sets as python does not have empty set literals. It is recommended to use set()
You could put your calls to input() in a comprehension:
set(input() for i in range(4))
You could use a for loop:
all = set()
for _ in range(4):
all.add(int(input())
print(all)
Don't forget that input gives you a string, so you should convert it to int or any type if needed excplicitly.
"_" in the for loop means that this variable is not important. But you can put whatever name you like.

Python unpacking gotcha (unexpected behavior) [duplicate]

This question already has answers here:
Python Multiple Assignment Statements In One Line
(5 answers)
How does Python's comma operator work during assignment?
(3 answers)
Closed 3 years ago.
Can anybody explain what's going on here? Why does this happen?
>>> b = "1984"
>>> a = b, c = "AB"
>>> print(a, b, c)
'AB', 'A', 'B'
This behavior really blows my mind.
Found this here
Assignment is a statement; it's defined to assign the far right side to the various targets from left to right. The rather dry language grammar description is:
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
So for example:
a = b = 1
assigns 1 to a, then assigns it again to b, roughly the same as if you did:
__specialtmp = 1
a = __specialtmp
b = __specialtmp
where __specialtmp is an unnamed temporary storage location (on CPython, it's just loaded on the top of the program stack, then duplicated into two references, then each reference is popped off for assignment).
This just adds iterable unpacking to the mix; expanding your code the same way, it would look like:
__specialtmp = "AB"
a = __specialtmp # Assigns original value to a
b, c = __specialtmp # Unpacks string as iterable of its characters, assigning "A" to b, and "B" to c
This won't always work mind you; if the thing being unpacked is an iterator, and you assign to the unpacked names first, the iterator will be exhausted and nothing useful will be available for the second assignment:
b, c = [*a] = iter("AB")
This unpacks "A" to b, and "B" to c, but when it gets to a, which in plain [*a] = iter("AB") would become ["A", "B"] (the star syntax capturing "remaining" values to a list), in this case, the iterator gets exhausted populating b and c and a gets nothing (the empty list, []).
Point is, while this trick works, I wouldn't recommend it in general. Initializing multiple names to the same immutable value is fine, but it's liable to bite you otherwise.
Such a cool question! Makes a lot of fun! :) Can be used at interviews :)
Ok, here we are
>>> b = "1984"
>>> a = b, c = "AB"
>>> print((a,b,c))
('AB', 'A', 'B')
>>> a = (b, c) = "AB"
>>> print((a,b,c))
('AB', 'A', 'B')
>>>
In python for multiple assignments, you can omit (...) and it looks like python parses this line similar to 2 lines
a = "AB"
b, c = "AB" # which is equal to (b, c) = "AB"
Some more examples
>>> a = b, c = "AB"
>>> print((a,b,c))
('AB', 'A', 'B')
>>> a = (b, c) = "AB"
>>> print((a,b,c))
('AB', 'A', 'B')
>>> a = "AB"
>>> b, c = "AB"
>>> print((a,b,c))
('AB', 'A', 'B')
>>>
It works using lists a well :)
>>> a = [b, c] = 'AB'
>>> print((a,b,c))
('AB', 'A', 'B')
>>>
Some more examples:
https://www.geeksforgeeks.org/unpacking-a-tuple-in-python/
https://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/
Let's make this a little simpler. Let's look at the following case
>>> b = 1
>>> b, c = (0, 2)
>>> print(b, c)
0, 2
Is it surprising that b is 0 and not 1? It shouldn't be since we assigning b to 0 and c to 2 when calling b, c = (0, 2) thanks to tuple unpacking.
Now to address the other part of the gotcha, let's take this example
>>> b = 1
>>> a = b = 0
>>> print (b)
0
Is it again surprising that b is 0 and not 1? Again, it shouldn't be since when calling a = b = 0, we've assigned both a and b to 0 with multiple assignment.
So coming back to the gotcha, the a = b, c = "AB" is just a combination of these two behaviors. b, c = "AB" will unpack "A" to b and "B" to c, and we're also assigning "AB" to a. While it looks like we're assigning a = b, we're really just doing the following two lines
>>> b = "1984"
>>> b, c = "AB"
>>> a = "AB"
Hopefully this breaks down where the tuple unpacking is happening and where the assignment is happening, and that it's not as confusing of a gotcha as it might look.

Categories