Concatenate strings to form a variable name - python

I have a number of variables in my python script containing integers e.g.,
lab19 = 100-50 #50
lab20 = 200-20 #180
I have a while loop that loops through an incrementing counter calling a function each time. The function needs to pass the variable, but the 19 and 20 parts of the variable name come from the counter.
I have tried this,
y = 1
while y < 21:
bundleRun('lab' + str(y))
y += 1
but that is passing the literal string 'lab1' value to the function.
How do I get my code to pass the variable value (e.g., 50) to my function based on the counter?
Thanks

I think you should store your data in a list or dict so it can be accessed by index or by key. But if you really need to access a local variable by name you can use locals()
y = 1
while y < 21:
a = locals()['lab' + str(y)] # value stored in variable a
y += 1

Whilst you can do this, you shouldn't.[^1] Dynamically created variables in python are a code smell (unlike e.g. TeX, where this kind of thing is routine).
Instead, store everything in a collection:
results = {"lab19": 50, "lab20": 180}
for lab, result in results.keys():
bundleRun(result)
Note that your while loop could be better written as:
for y in range(1,21):
...
If you really do need to do this, the other answer with locals() is the way to go.
[^1] but it could be worse: you're only trying to access them. Perhaps you have to do this---but if you have control over the variables the pythonic way is to use a collection.

Related

List of empty variables in Python

Is there any possibility of creating a list of variables/names* that have not been defined yet, and then loop through the list at a later stage to define them?
Like this:
varList = [varA, varB, varC]
for var in varList:
var = 0
print(varList)
>>>[0, 0, 0]
The reason I'm asking is because I have a project where I could hypothetically batch fill 40+ variables/names* this way by looping through a Pandas series*. Unfortunately Python doesn't seem to allow undefined variables in a list.
Does anyone have a creative workaround?
EDIT: Since you asked for the specific problem, here goes:
I have a Pandas series that looks like this (excuse the Swedish):
print(Elanv)
>>>
Förb. KVV PTP 5653,021978
Förb. KVV Skogsflis 0
Förb. KVV Återvinningsflis 337,1416119
Förb. KVV Eo1 6,1
Förb. HVC Återvinningsflis 1848
Name: Elanv, dtype: object
I want to store each value in this array to a set of new variables/names*, the names of which I want to control. For example, I want the new variable/name* containing the first value to be called "förbKVVptp", the second one "förbKVVsflis", and so forth.
The "normal" option is to assign each variable manually, like this:
förbKVVptp, förbKVVsflis, förbKVVåflis = Elanv.iloc[0], Elanv.iloc[1], Elanv.iloc[2] ....
But that creates a not so nice looking long bunch of code just to name variables/names*. Instead I thought I could do something like this (obviously with all the variables/names*, not just the first three) which looks and feels cleaner:
varList = [förbKVVptp, förbKVVsflis, förbKVVåflis]
for i, var in enumerate(varList): var = Elanv.iloc[i]
print(varList)
>>>[5653,021978, 0, 337,1416119]
Obviously this becomes pointless if I have to write the name of my new variables/names* twice (first to define them, then to put them inside the varList) so that was why I asked.
You cannot create uninitialized variables in python. Python doesn't really have variables, it has names referring to values. An uninitialized variable would be a name that doesn't refer to a value - so basically just a string:
varList = ['förbKVVptp', 'förbKVVsflis', 'förbKVVåflis']
You can turn these strings into variables by associating them with a value. One of the ways to do that is via globals:
for i, varname in enumerate(varList):
globals()[varname] = Elanv.iloc[i]
However, dynamically creating variables like this is often a code smell. Consider storing the values in a dictionary or list instead:
my_vars_dict = {
'förbKVVptp': Elanv.iloc[0],
'förbKVVsflis': Elanv.iloc[1],
'förbKVVåflis': Elanv.iloc[2]
}
my_vars_list = [Elanv.iloc[0], Elanv.iloc[1], Elanv.iloc[2]]
See also How do I create a variable number of variables?.
The answer to your question is that you can not have undefined variables in a list.
My solution is specific to solving this part of your problem The reason I'm asking is that I have a project where I could hypothetically batch fill over 100 arrays this way by looping through a Pandas array.
Below solution prefills the list with None and then you can change the values in the list.
Code:
varList = [None]*3
for i in range(len(varList)):
varList[i] = 0
print(varList)
Output:
[0, 0, 0]
So something you are trying to do in your example that won't do what you expect, is how you are trying to modify the list:
for var in varList:
var = 0
When you do var = 0, it won't change the list, nor the values of varA, varB, varC (if they were defined.)
Similarly, the following won't change the value of the list. It will just change the value of var.
var = mylist[0]
var = 1
To change the value of the list, you need to do an assignment expression on an indexed item on the list:
mylist = [None, None, None]
for i in range(len(mylist)):
mylist[i] = 0
print(mylist)
Note that by creating a list with empty slots before assigning the value is inefficient and not pythonic. A better way would be to just iterate through the source values, and append them to a list, or even better, use a list comprehension.

How does this for-loop within this dictionary work exactly?

Currently I'm learning Python text sentiment module via this online course and the lecturer failed to explain in enough detail how this piece of code works. I tried searching each piece of code individually to try piece together how he did it but it makes no sense to me.
So how does this code work? Why is there a for loop within dictionary braces?
What is the logic behind x before the for y in emotion_dict.values() then for x in y at the end?
What is the purpose behind emotion_dict=emotion_dict within the parentheses? Wouldn't just emotion_dict do?
def emotion_analyzer(text,emotion_dict=emotion_dict):
#Set up the result dictionary
emotions = {x for y in emotion_dict.values() for x in y}
emotion_count = dict()
for emotion in emotions:
emotion_count[emotion] = 0
#Analyze the text and normalize by total number of words
total_words = len(text.split())
for word in text.split():
if emotion_dict.get(word):
for emotion in emotion_dict.get(word):
emotion_count[emotion] += 1/len(text.split())
return emotion_count
1 and 2
The line emotions = {x for y in emotion_dict.values() for x in y} uses a set comprehension. It builds a set, not a dictionary (though dictionary comprehensions also exist and look somewhat similar). It is shorthand notation for
emotions = set() # Empty set
# Loop over all values (not keys) in the pre-existing dictionary emotion_dict
for y in emotion_dict.values():
# The values y are some kind of container.
# Loop over each element in these containers.
for x in y:
# Add x to the set
emotions.add(x)
The x right after the { in the original set comprehension signifies which value to store in the set. In all, emotions is just a set (with no repeats) of all elements within all containers within the dictionary emotion_dict. Try printing out emotion_dict and emotion and compare.
3
In the function definition,
def emotion_analyzer(text, emotion_dict=emotion_dict):
the emotion_dict=emotion_dict means that the local variable with name emotion_dict gets set to the global variable similarly named emotion_dict, if you do not pass anything as the second argument. This is an example of a default argument.

Accessing dictionary from function in Python

So I'm trying to take variables from one function, and continue to use them in another. I'm getting a KeyError when I try to run this. Any ideas? Cheers!
def find_pos():
x = 1
y = 12
z = 3
return { 'x':x, 'y':y, 'z':z }
def create(x, y, z):
blah = x + y + z
print 'blah'
testReturn = find_pos()
create(testReturn[x], testReturn[y], testReturn[z])
You are trying to access your dictionary by referring to your keys by a variable name that you have not defined. This is incorrect. Your dictionary keys were created using strings 'x', 'y' and 'z'. Therefore, you must access your data in your dictionary as such.
You want to do this:
create(testReturn['x'], testReturn['y'], testReturn['z'])
Better yet, since you seem to be doing some math operations on it, you can even use get instead, which will return None by default if it can't find the key. So, in your case, you can change this default, and set it to 0 instead:
create(testReturn.get('x', 0), testReturn.get('y', 0), testReturn.get('z', 0))

Python references to references in python

I have a function that takes given initial conditions for a set of variables and puts the result into another global variable. For example, let's say two of these variables is x and y. Note that x and y must be global variables (because it is too messy/inconvenient to be passing large amounts of references between many functions).
x = 1
y = 2
def myFunction():
global x,y,solution
print(x)
< some code that evaluates using a while loop >
solution = <the result from many iterations of the while loop>
I want to see how the result changes given a change in the initial condition of x and y (and other variables). For flexibility and scalability, I want to do something like this:
varSet = {'genericName0':x, 'genericName1':y} # Dict contains all variables that I wish to alter initial conditions for
R = list(range(10))
for r in R:
varSet['genericName0'] = r #This doesn't work the way I want...
myFunction()
Such that the 'print' line in 'myFunction' outputs the values 0,1,2,...,9 on successive calls.
So basically I'm asking how do you map a key to a value, where the value isn't a standard data type (like an int) but is instead a reference to another value? And having done that, how do you reference that value?
If it's not possible to do it the way I intend: What is the best way to change the value of any given variable by changing the name (of the variable that you wish to set) only?
I'm using Python 3.4, so would prefer a solution that works for Python 3.
EDIT: Fixed up minor syntax problems.
EDIT2: I think maybe a clearer way to ask my question is this:
Consider that you have two dictionaries, one which contains round objects and the other contains fruit. Members of one dictionary can also belong to the other (apples are fruit and round). Now consider that you have the key 'apple' in both dictionaries, and the value refers to the number of apples. When updating the number of apples in one set, you want this number to also transfer to the round objects dictionary, under the key 'apple' without manually updating the dictionary yourself. What's the most pythonic way to handle this?
Instead of making x and y global variables with a separate dictionary to refer to them, make the dictionary directly contain "x" and "y" as keys.
varSet = {'x': 1, 'y': 2}
Then, in your code, whenever you want to refer to these parameters, use varSet['x'] and varSet['y']. When you want to update them use varSet['x'] = newValue and so on. This way the dictionary will always be "up to date" and you don't need to store references to anything.
we are going to take an example of fruits as given in your 2nd edit:
def set_round_val(fruit_dict,round_dict):
fruit_set = set(fruit_dict)
round_set = set(round_dict)
common_set = fruit_set.intersection(round_set) # get common key
for key in common_set:
round_dict[key] = fruit_dict[key] # set modified value in round_dict
return round_dict
fruit_dict = {'apple':34,'orange':30,'mango':20}
round_dict = {'bamboo':10,'apple':34,'orange':20} # values can even be same as fruit_dict
for r in range(1,10):
fruit_set['apple'] = r
round_dict = set_round_val(fruit_dict,round_dict)
print round_dict
Hope this helps.
From what I've gathered from the responses from #BrenBarn and #ebarr, this is the best way to go about the problem (and directly answer EDIT2).
Create a class which encapsulates the common variable:
class Count:
__init__(self,value):
self.value = value
Create the instance of that class:
import Count
no_of_apples = Count.Count(1)
no_of_tennis_balls = Count.Count(5)
no_of_bananas = Count.Count(7)
Create dictionaries with the common variable in both of them:
round = {'tennis_ball':no_of_tennis_balls,'apple':no_of_apples}
fruit = {'banana':no_of_bananas,'apple':no_of_apples}
print(round['apple'].value) #prints 1
fruit['apple'].value = 2
print(round['apple'].value) #prints 2

Set variables from variables?

I've got many, many strings, all formatted like this: "lot1", "lot2", "lot3"... What I'd like to do is use a function argument to determine which variable to use. Here's a pseudoexample:
def printlot(someInt):
print lot%i % (someInt)
Basically, I'd like to use multiple strings to form the name of another string to act with. This seems simple enough, but I haven't learned how to do it in my two years of Pythoning.
What nneonneo said is correct, but you're really going to want to use a dict explicitly. That is, you want to do this:
lot_data = {'lot1': 10, 'lot2': 20, 'lot3': 30}
i = 2
print lot_data['lot%d' % i]
Instead of this:
lot1 = 10
lot2 = 20
lot3 = 30
i = 2
print vars()['lot%d' % i]
You can access all visible variables as a dictionary using the vars builtin function:
vars()['lot%d' % someInt]
Different scopes can be accessed with globals or locals.
Note, however, that this is generally considered "unpythonic" behaviour. Instead of creating many similarly-named variables, a more Pythonic approach would be to make a list or dictionary.

Categories