def function(x):
x = 4
variable = 0
function(variable)
print(variable)
This would output 0 but is there a way that it outputs 4? And also it should be without return.
First of all, I'd suggest you take a look to this nice explanation about python names and values. Now, one possible way to achieve what you want would be using a mutable structure as a dictionary, so you can pass your variable inside, something similar to this would do it:
def function(dct):
dct['variable'] = 4
dct = {
'variable': 0
}
function(dct)
print(dct['variable'])
More info can be found in python docs
Related
I have a Python script called module.py with several functions in it, like this:
def foo_1():
var = 1
return
def foo_2():
var = 2
return
def foo_3():
var = 3
return
def foo_4():
var = 4
return
Each of the functions (foo_1, foo_2, ...) defines a unique value for the variable named var, and I am looking for a way to grab this value from each of the functions. Is this possible in Python? It is crucial to my project that each of the variables var have the same local name in their respective function.
I have already been able to grab a list of all the functions as follows:
from inspect import getmembers, isfunction
import module
function_list = [pair[0] for pair in getmembers(module, isfunction)]
Which returns a list of all the functions names [foo_1, foo_2, foo_3, foo_4]. Now, I am looking for a way to iterate through all the functions and grab the value of var in each one — something like this:
var_value_tuples = []
for function in function_list:
var_values.append((function, function.var))
Thank you in advance for any help.
A different way to achieve this, that is less of an anti-pattern and does not require introspection (also does not impose any specific function signature):
vars = { "foo_1": 1, "foo_2": 2, "foo_3": 3, "foo_4": 4 }
def foo_1():
var = vars["foo_1"]
return
def foo_2():
var = vars["foo_2"]
return
def foo_3():
var = vars["foo_3"]
return
def foo_4():
var = vars["foo_4"]
return
Some things to consider:
do these all need to be distinct functions if they have such similar implementations
since the functions seem to have a one to one mapping, can you use a list or some other data structure to map from vars to functions
Ultimately this is an XY Problem. You should add more context or outline the overall problem you are trying to solve.
you can try something like
foo_1.__code__.co_varnames gives list of all local variables in the function
foo_1.__code__.co_consts gives all the constant values,first one being the default return value i.e. None
def foo_1():
var = 1
var2 = 2
return
variables = dict(zip(foo_1.__code__.co_varnames, foo_1.__code__.co_consts[1:]))
print(variables)
{'var': 1, 'var2': 2}
I came across closures in python, and I've been tinkering around the subject.
Please Correct me if I'm wrong here, but what I understood for when to use closures (generally) is that it can be used as a replacement of small classes (q1) and to avoid the use of globals (q2).
Q1: [replacing classes]
Any instance created from the datafactory class will have it's own list of data, and hence every appending to that object's list will result in an incremental behavior. I understand the output from an OO POV.
class datafactory():
def __init__(self):
self.data = []
def __call__(self, val):
self.data.append(val)
_sum = sum(self.data)
return _sum
incrementwith = datafactory()
print(incrementwith(1))
print(incrementwith(1))
print(incrementwith(2))
OUTPUT:
1
2
4
I tried replacing this with a closure, it did the trick, but my understanding to why/how this is happening is a bit vague.
def data_factory():
data = []
def increment(val):
data.append(val)
_sum = sum(data)
return _sum
return increment
increment_with = data_factory()
print(increment_with(1))
print(increment_with(1))
print(increment_with(2))
OUTPUT:
1
2
4
What I'm getting is that the data_factory returns the function definition of the nested increment function with the data variable sent along as well, I would've understood the output if it was something like this:
1
1
2
But how exactly the data list persists with every call?
Shouldn't variables defined in a function die after the function finishes execution and get regenerated and cleared out with the next fn call?
Note: I know that this behavior exists normally in a function defined with default parameters like def func(val, l = []): where the list will not be cleared on every fn call, but rather be updated with a new element/append, which is also something that I do not fully understand.
I would really appreciate an academic explanation to what happens in both scenarios (OO and closures).
Q2: [replacing use of global]
Is there a way using closures to increment the following variable without using globals or a return statement ?
a = 0
print("Before:", a) # Before: 0
def inc(a):
a += 1
print("After:", a) # After: 0
Thank you for your time.
For the first question, I found after some digging that passing mutables as default parameters isn't really a good move to make:
https://florimond.dev/blog/articles/2018/08/python-mutable-defaults-are-the-source-of-all-evil/#:~:text=of%20this%20mess.-,The%20problem,or%20even%20a%20class%20instance.
This question already has answers here:
How do I create variable variables?
(17 answers)
Closed last year.
I am looking to create a variable name from two strings in Python, e.g.:
a = "column_number"
b = "_url1"
and then be able to get a variable name "column_number_url1" that I can use.
I appreciate this is in general not a good idea - there are numerous posts which go into why it is a bad idea (e.g. How do I create a variable number of variables? , Creating multiple variables ) - I mainly want to be able to do it because these are all variables which get defined elsewhere in the code, and want a easy way of being able to re-access them (i.e. rather than to create thousands of unique variables, which I agree a dictionary etc. would be better for).
As far as I can tell, the answers in the other posts I have found are all alternative ways of doing this, rather than how to create a variable name from two strings.
>>> a = "column_number"
>>> b = "_url1"
>>> x = 1234
>>> globals()[a + b] = x
>>> column_number_url1
1234
The reason that there aren't many posts explaining how to do this is because (as you might have gathered) it's not a good idea. I guarantee that your use case is no exception.
In case you didn't notice, globals() is essentially a dictionary of global variables. Which implies that you should be using a dictionary for this all along ;)
You can use a dictionary:
a = "column_number"
b = "_url1"
obj = {}
obj[a+b] = None
print obj #{"column_number_url1": None}
Alternatively, you could use eval, but remember to always watch yourself around usage of eval/exec:
a = "column_number"
b = "_url1"
exec(a+b+" = 0")
print column_number_url1 #0
eval is evil
As an alternative to Joel's answer, a dictionary would be much nicer:
a = "column_number"
b = "_url1"
data = {}
data[a+b] = 42
I am trying to define a function in Python. It should look like this:
def myfunction(Peter_1, Amy_1, Peter_2, Amy_2, Peter_3, Amy_3,....Peter_50,Amy_50):
Peter_1 = 100
Amy_1 = 20
Peter_2 = 90
Amy_2 = 4
...
...
I am using a small software writing in Python to do optimazation. The software is like that, after I define myfunction , I should write,
parameter1 = Parameter("Peter_1", (90,100),1)
parameter2 = Parameter("Amy_1", (15,25),1)
...
...
parameter99 = Parameter("Peter_50", (70,100),1)
parameter100 = Parameter("Amy_50", (15,25),1)
Parameter is the software defined function, the first argument of Parameter should be a string, and it has to be exactly the name I defined in myfunction. Then the software knows that the first parameter which need to be optimazed is Peter_1.
I donot want to type all the 100 parameters, can anyone help me?
This is a bad code smell. You should wrap the arguments in an object. For example a dictionary.
Something like this:
def myfunction(people):
for person_name in people.iterkeys():
people[person_name] = 100
my_people = {}
my_people['Peter'] = 0
my_people['Simon'] = 0
myfunction(my_people)
print my_people
But my real concern is that you initialize the value in the function. Why not beforehand?
my_people = {}
my_people['Peter'] = 100
my_people['Simon'] = 90
That way you don't need the function.
you can even use python *args syntax. For example something like this:
def foo(*args):
for i in args:
print(i)
foo(1,2)
foo(1,2,3,4,5,6,7,8)
#output:
1
2
#second run:
1
2
3
4
5
6
7
8
Well, RvdK's answer works, but if you MUST write it the way you indicated in your question, then you should consider using the exec() function. That way you can write a small code inside your script that writes this function as a string for you. Then with exec() you can actually use the resulting string as an active part of the code.
Although, I would recommend that you use lists or tuples if that is a possibility.
I am trying to do the following in python: I have a list which contains some string values. The list looks like this:
parameters = ['RH', 'WindSp_Avg', 'WindDir']
What I want to do - and I really hope the question is not ridiculous - is to create three lists which each of them have the name of the "parameters" list.
For example:
RH = []
WindSp_Avg = []
WindDir = []
I am new in python and although I had searched a bit online I couldn't find some elegant way to do something like this.
I am trying something like this:
for i in parameters:
parameters[0] = []
But it doesn't seem to work. Any suggestions?
Thanks
Dimitris
What you are trying to do is very unsafe and is against all good practices. Is there a problem in simply creating a dictionary?
myVars = {}
for param in parameters:
myVars[param] = []
WARNING The following code is for educational purposes! DO NOT USE IT IN REAL CODE!
You can do a hard hack to add dynamically a variable to the local variables inside a function. Normally locals() represent all local variables. However simply adding to that dictionary won't solve the problem. There is a hack to force Python to reevaluate locals by using exec, for example:
def test():
for param im parameters:
locals()[param] = []
exec ""
print WindSp_Avg
and result:
>>> test()
[]
parameters = ['RH', 'WindSp_Avg', 'WindDir']
for i in parameters:
vars()[i] = [];
print locals()
To create a variable you can do so:
parameters = ['RH', 'WindSp_Avg', 'WindDir']
for i in parameters:
exec("%s = []" % i);
print vars()
you could something like this:
code = "{0} = []"
for i in parameters:
codeobj = compile(code.format(i), "/dev/null", "single")
eval(codeobj)
but i think tha's very unsafe. Because it could be something in parameters and that will be excuted by the eval. So please only use this if it's only really necessary and security is less important.