I want a for loop in Python that can modify variables in the iterator, not just handle the value of the variables. As a trivial example, the following clearly does not do what I want because b is still a string at the end.
a = 3
b = "4"
for x in (a, b):
x = int(x)
print("b is %s" % type(b))
(Result is "b is a <class 'str'>")
What is a good design pattern for "make changes to each variable in a long list of variables"?
Short answer: you can't do that.
a = "3"
b = "4"
for x in (a, b):
x = int(x)
Variables in Python are only tags that references values. Theres is not such thing as "tags on tags". When you write x = int(x) if the above code, you only change what x points to. Not the pointed value.
What is a good design pattern for "make changes to each variable in a long list of variables"?
I'm not sure to really understand, but if you want to do things like that, maybe you should store your values not as individual variables, but as value in a dictionary, or as instance variables of an object.
my_vars = {'a': "3",
'b': "4" }
for x in my_vars:
my_vars[x] = int(my_vars[x])
print type(my_vars['b'])
Now if you're in the hackish mood:
As your variables are globals they are in fact stored as entries in a dictionary (accessible through the globals() function). So you could change them:
a = "3"
b = "4"
for x in ('a', 'b'):
globals()[x] = int(globals()[x])
print type(b)
But, as of myself, I wouldn't call that "good design pattern"...
As mentioned in another answer, there's no way to update a variable indirectly. The best you can do is assign it explicitly with unpacking:
>>> a = 3
>>> b = 4
>>> a, b = [int(x) for x in a, b]
>>> print "b is %s" % type(b)
b is <type 'int'>
If you have an actual list of variables (as opposed to a number of individual variables you want to modify), then a list comprehension will do what you want:
>>> my_values = [3, "4"]
>>> my_values = [int(value) for value in my_values]
>>> print(my_values)
[3, 4]
If you want to do more complicated processing, you can define a function and use that in the list comprehension:
>>> my_values = [3, "4"]
>>> def number_crunching(value):
... return float(value)**1.42
...
>>> my_values = [number_crunching(value) for value in my_values]
>>> print(my_values)
[4.758961394052794, 7.160200567423779]
Related
The code
a={'k1':['a',2,3]}
b={'k2':[2,'b',4]}
for i in [a,b]:
print(i)
prints out the value of a and b. But what I actually wanted it to print the dictionary names, i.e.
a
b
My current solution is this:
a={'k1':['a',2,3]}
b={'k2':[2,'b',4]}
for i in [a,b]:
if i is a:
print('a')
elif i is b:
print('b')
Is there a better approach?
There is no way to get the name of a value. There's also never a need to.
Names refer to values. Many names can refer to the same value. Thus, there cannot be a "true name" for any given object as all names are equal.
Consider
>>> x = 5
>>> y = x
>>> x is y
True
Now, what's the name of the value 5? It does not make sense.
Consider
>>> x = [1,2,3]
>>> y = x[:] # shallow copy of x
>>> x is y
False
Now, what's the name of the list [1,2,3], which exists twice? It does not make sense.
If you are desperate to give your dictionaries a persistent name, add it as a key-value pair, e.g.
>>> mydic = {1:2, 'name':'Bob'}
>>> mydic['name']
'Bob'
But consider carefully why you actually want to do this. Chances are that you don't even want to.
So, I have a python script which requires an input from the terminal. I have 20 different arrays and I want to print the array based on the input.
This is the code minus the different arrays.
homeTeam = raw_input()
awayTeam = raw_input()
a = (homeTeam[0])+(awayTeam[3])/2
b = (hometeam[1])+(awayTeam[2])/2
So, effectively what I want to happen is that homeTeam/awayTeam will take the data of the array that is typed.
Thanks
You may take input as the comma separated (or anything unique you like) string. And call split on that unique identifier to get list (In Python array and list are different).
Below is the example:
>>> my_string = raw_input()
a, b, c, d
>>> my_list = my_string.split(', ')
>>> my_list
['a', 'b', 'c', 'd']
Since you are having your list now, you already know what you need to do with it.
Alternatively, you may also extract list from raw_input by using eval. But it is highly recommended not to use eval. Read: Is using eval in Python a bad practice?
Below is the example:
>>> my_list = eval(raw_input())
[1, 2, 3, 4, 5]
>>> my_list[2]
3
Instead of 20 individual arrays you could use a dictionary.
d = {"team1": "someValue",
"team2": "anotherValue",
...
}
Then you can retrieve the values of a team by its name:
x = raw_input("team1")
d[x] will now return "someValue".
In your particular case, you can use arrays for the values of the dictionary, for example:
d = {"team1": [value1, value2, ...],
"team2": [...],
...
}
Now d[x] returns the array [value1, value2, ...].
Complete example
Finally, you could wrap all of this into a single function f:
def f():
homeTeam = d[raw_input("Enter home team: ")]
awayTeam = d[raw_input("Enter away team: ")]
a = (homeTeam[0] + awayTeam[3])/2
b = (homeTeam[1] + awayTeam[2])/2
return a, b
By calling f() the user will be prompted for two team names. And the function will return the values of both teams in form of a tuple.
You can take raw_input() as string and then you can use split function to make it array. While doing arithmetic stuff you need to do type casting. for example,
homeTeam = raw_input() ### 1,2,3,4
homeTeam = homeTeam.split(",")
awayTeam = raw_input() ### 5,6,7,8
awayTeam = awayTeam.split(",")
a = (int(homeTeam[0]) + int(awayTeam[3]))/2
b = (int(hometeam[1]) + int(awayTeam[2]))/2
I think this should be simple but I'm not sure how to do it. I have a tuple of list variables:
A = (a,b,c)
where
a = [1,2,3,...]
b = [2,4,6,4,...]
c = [4,6,4,...]
And I want to make a tuple or list where it is the names of the variables. So,
A_names = ('a','b','c')
How could I do this? My tuple will have more variables and it is not always the same variables. I tried something like
A_names = tuple([str(var) for var in A])
but this did not work.
My connection was messed up so I couldn't post this earlier but I believe this solves your problem with out using a dictionary.
import inspect
def retrieve_name(var):
local_vars = inspect.currentframe().f_back.f_locals.items()
return [var_name for var_name, var_val in local_vars if var_val is var]
a = [1,2,3]
b = [2,4,6,4]
c = [4,6,4]
a_list = (a,b,c)
a_names = []
for x in a_list:
a_names += (retrieve_name(x)[0])
print a_names
outputs ['a', 'b', 'c']
The problem with what you are asking is that doing A = (a, b, c) does not assign the variables "a", "b" and "c" to the tuple A. Rather, you are creating a new reference to each of the objects referred to by those names.
For example, if I did A = (a,), a tuple with a single object. I haven't assigned the variable "a". Instead, a reference is created at position 0 in the tuple object. That reference is to the same object referred to by the name a.
>>> a = 1
>>> b = 2
>>> A = (a, b)
>>> A
(1, 2)
>>> a = 3
>>> A
(1, 2)
Notice that assigning a new value to a does not change the value in the tuple at all.
Now, you could use the locals() or globals() dictionaries and look for values that match those in A, but there's no guarantee of accuracy since you can have multiple names referring to the same value and you won't know which is which.
>>> for key, val in locals().items():
if val in A:
print(key, val)
('a', 1)
('b', 2)
Assuming you want dynamic/accessible names, you need to use a dictionary.
Here is an implementation with a dictionary:
my_variables = {'a': [1,2,3,...],
'b': [2,4,6,4,...],
'c': [4,6,4,...]}
my_variable_names = my_variables.keys()
for name in my_variable_names:
print(my_variables[name])
Just out of academic interest:
dir() will give you a list of the variables currently visible,
locals() gives the list of local variables
globals() (guess)
Note that some unexpected variables will show up (starting and ending in __), which are already defined by Python.
A = {'a' : [1,2,3,...],
'b' : [2,4,6,4,...],
'c' : [4,6,4,...]}
A_names = A.keys()
for name in A_names:
print(A[name])
Then you can always add a new value to the dictionary by saying:
A.update({'d' : [3,6,3,8,...], 'e' : [1,7,2,2,...]})
Alternatively, you can change the value of an item by going:
A.update({'a' : [1,3,2,...]})
To print a specific value, you can just type:
print(A['c'])
In some other programming languages I am used to, there was a way to dynamically create and call variables. How to do this in Python?
For example let's suppose variables called test1; test2 etc. up to test9, and I want to call them like this:
for n in range(1,10):
print concatenate('test', n)
Of course, the function concatenate is the one I am looking for.
What is the command to combine strings, integers and regular expressions in this way?
My example was a bad one, that made some of the answers suggest dictionary, or some other similar methods. It's either I am not too confident with them, or I can't use them in all cases. Here's another example:
Let's suppose we have a table of 4 rows and 4 columns, and the table has some numbers in it. I want to do some special mathematical operations, which has the row number, column number and the variable as inputs, and it outputs another row-column pair for another mathematical operation.
Logic suggests me that te easiest way to do this would be to have 16 variables, having row and column number in their names. And if I could do operations with the names of the variables, and also return the result and call it as another varialbe, the problem would be easy.
What about this context?
What you think you want is this:
>>> test1 = 'spam'
>>> test2 = 'eggs'
>>> for i in [1, 2]:
... print locals()['test' + str(i)]
...
spam
eggs
But what you really want is this:
>>> values = 'spam', 'eggs'
>>> my_namespace = {'test' + str(i): v for i, v in enumerate(values, 1)}
>>> for k, v in sorted(my_namespace.items()):
... print v
...
spam
eggs
Keep data out of your variable names.
You could use globals, which returns a dictionary of what is in the global scope:
>>> test1 = 'a'
>>> test2 = 'b'
>>> test3 = 'c'
>>> globals()
{'test1': 'a', 'test3': 'c', 'test2': 'b', '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}
>>> for n in range(1, 4):
... print globals()["test" + str(n)] # Dynamically access variables
...
a
b
c
>>> for n in range(1, 4):
... globals()["dynamic" + str(n)] = n # Dynamically create variables
...
>>> dynamic1
1
>>> dynamic2
2
>>> dynamic3
3
>>>
However, I do not recommend that you actually do this. It is ugly, hackish, and really just a bad practice.
It would be much better to do away with your numbered variables and instead use a list, which will automatically number its items by index:
>>> lst = ['a', 'b', 'c']
>>> lst[0] # Equivalent to test1
'a'
>>> lst[1] # Equivalent to test2
'b'
>>> lst[2] # Equivalent to test3
'c'
>>> for i in lst: # You can iterate directly over the list too
... print i
...
a
b
c
>>> lst.append('d') # "Creating" a new object is easy and clean
>>> lst
['a', 'b', 'c', 'd']
>>>
Basically, instead of test1, test2, test3...you now have lst[0], lst[1], lst[2]...
Python doesn't do that as well as some languages, I don't think, but they have a couple useful functions. eval() lets you evaluate a string as if it were a statement or variable, printing out the value of a given statement.
https://docs.python.org/2/library/functions.html#eval
>>> test9 = 5
>>> eval("test9")
5
for n in range(10):
eval("test" + str(n)) # Need to convert ints to strings to make string concatenation work.
If you wanted to assign values to variables, you'd use exec().
https://docs.python.org/2/reference/simple_stmts.html#exec
>>> test9 = 6
>>> exec("test9 = 7")
>>> print test9
7
Simply:
print "test" + n
or
print("test" + n);
Context: I needed to randomly erase some precise element of a few lists of numbers, extracting some random indexes and saving them in a set called aleaindex (done, it properly works, thanks to some SO users' help). Now, I'd like to substitute the old lists a, b, etc with the new, eventually shorter ones newa, newb, etc. Here is the function:
def myfunction(N, other_parameters, a, b, c):
...
while (...):
aleaindex.add(random.randint(..., ...))
...
new_a = [v for i, v in enumerate(a) if i not in aleaindex]
while a: a.pop()
a = new_a[:]
...
and so on for the other lists b, c, etc.
Problem: the function seems to correctly modify them within the module (checked by printing) but then, when I print the modified lists outside the module, that is in the "main" file, lists are as they had not modified. Where am I wrong?
This line:
a=new_a[:]
overwrites the variable a with a new object. Outside the function or module, the old object is still pointed at by a (or whatever it was called there). Try:
new_a = [v for i, v in enumerate(a) if i not in aleaindex]
while a:
a.pop()
a[:] = new_a[:]
Explanation
To see this, just try the following.
>>> a = [1,2,3,4]
>>> b = a
>>> print b
[1, 2, 3, 4]
>>> a[:] = [2,3]
>>> print b
[2, 3]
>>> a = [5]
>>> print b
[2, 3]
Example in function!
If the variable is mutable (and a normal list is), this works:
>>> def f(a):
... a[0] = 2
>>> b = [3]
>>> f(b)
>>> print b
[2]
Variables are not passed by value - you can edit a mutable value.
I do not know what you are trying to do but from your snippets you are clearly lost. Your code does not make much sense and there are more more than one problem. Nonetheless, the problem you asked about - why the list is not fully changed? - seems to be related to this loop:
while a: a.pop()
a = new_a[:]
Suppose we call your function this way:
list1 = [1, 2, 3, 4, 5, 6, 7]
myfunction(N, other_parameters, list1, [], [])
What will happen is, when you call the first line, you will get a variable called list1 and it will point to a list:
When you call the function myfunction(), the function, among other things, create a variable called a which will point to the same list pointed by list1:
So far, so good. Then we get at the loop below:
while a:
a.pop()
a = new_a[:]
In the first line of it (a.pop()), you get an item out of the list. Since both variables a and list1 points to the same list, you would see the same result...
...if it were not for the next line of the loop (a = new_a[:]). In this line, you are making the a variable to point to another list:
Now, every operation you execute on a will be in this list, which is in no way related to list1. For example, you can execute a.pop() at the next iteration to get it:
However, it makes no sense at all, because the line a = new_a[:] will replace the list pointed to a again for yet another different list:
So, what is the solution? I don't know. As I have said, it is not possible (to me, at least) to make sense from your code. You have to reflect a bit more about what you are trying to do and explain it to us, with a bit more of context.
There is no function in the code you have posted. I suspect the problem is that you are not returning the new value.
Your code likely does something like:
a = "foo"
def func():
a = "bar" # uh-oh this not the same as the global a
func()
At this point global a is unchanged because the a local to func is not the same variable.
You want to do:
a = "foo"
def func():
return "bar"
a = func()
That code assigns to the a in global scope, changing it.