I am using a method for storing and recalling global variables in Python. I like it. It seems to work for me. I am not a coder though. I know nothing about this stuff. So, wondering where its limitations will be - how and when I will regret using it in future.
I create a function that will update the value if passed a new one or return the existing value as below:
def global_variable(new_value = None):
# a function that both stores and returns a value
# first deal with a new value if present
if new_value != None
# now limit or manipulate the value if required
# in this case limit to integers from -10 to 10
new_value = min(new_value, 10)
global_variable.value = int(max(new_value, -10))
# now return the currently stored value
try:
# first try and retrieve the stored value
return_value = global_variable.value
except AttributeError:
# and if it read before it is written set to its default
# in this case zero
global_variable.value = 0
return_value = global_variable.value
# either way we have something to return
return return_value
store like this
global_variable(3)
retrieve like this
print(global_variable())
You can just use global variables. If you need to change them within a function you can use the global keyword:
s = 1
def set():
global s
s = 2
print(s)
set()
print(s)
> 1
> 2
Related
Suppose I have a Python function foo which takes a default argument, where that default is set to some global variable. If I now change that global variable before calling the function, the default argument is still set to the original value of that global variable.
For example:
x = 1
def foo(a=x):
print a
x = 2
foo()
This prints 1, instead of 2.
How should I be writing my code, so that I can change this global variable, and have it update this default argument?
A default variable is only evaluated and set once. So Python makes a copy of the reference and from then on, it always passes that reference as default value. No re-evaluation is done.
You can however solve this by using another object as default object, and then use an if statement to substitute it accordingly. Something like:
the_default = object()
x = 1
def foo(a = the_default):
if a is the_default:
a = x
print a
x = 2
foo()
Note that we use is to perform reference equality. So we check if it is indeed the default_object. You should not use the the_default object somewhere else in your code.
In many Python code, they use None as a default (and thus reduce the number of objects the construct). For instance:
def foo(a = None):
if a is None:
a = x
print a
Note however that if you do that, your program cannot make a distinction between a user calling foo() and foo(None) whereas using something as the_object makes it harder for a user to obtain a reference to that object. This can be useful if None would be a valid candidate as well: if you want foo(None) to print 'None' and not x.
Short example:
def Tk1():
x = 1
def Tk2():
x = 2
I want "x" to not change down the code into the subsequent variable. Can I have both "x" assigned to different values and not mess up the code within the def?
Yes a variable that is defined in the function, will always stay the same in that specific function, however if you define it outside the two functions the value can change depending on which function you call first:
a = 0
def f_a():
a = 10
return a
def f_b():
a = 4
return a
print(f_a())
print(f_b())
Will return this result:
10
4
The way you showed in your question defines the variable inside the function meaning it is local to that specific function. Note the fact it isn't a global variable.
This question already has answers here:
What is the Python equivalent of static variables inside a function?
(28 answers)
Closed 3 years ago.
Is there a way that a function can remember its previous output and use that value during the next call to the function? For instance, assume there is a function, runningTotal with a single argument x that returns x on the first call to runningTotal but x + prevOutput for every call after that. Is there a way to write such a function in python?
I am aware that this could be easily achieved by using a global variable in the function or by saving the previous value to a new variable, but I would like to avoid these solutions if possible. The reason I'm looking for an alternate solution is because this is one function in a program I'm working on with other people and I would like to avoid having to create more global variables than already established.
Yes, but to avoid too much hackery or GLOBAL variables we'll probably want to use a class.
In python a class can be treated as function with a magic function (method) inside the class named __call__.
Your question might be better written: what's the best way to have a function in python that has internal state?
Let's say we have the runningTotal function defined using a global variable as:
TOTAL = 0
def runningTotal(inc):
global TOTAL
TOTAL += inc
return TOTAL
Answer Ok so lets define a class that will behave the same way as the above function but without a global variable:
class StatefulFunction:
running_total = 0
def __call__(self, inc):
self.running_total += inc
return self.running_total
# create the stateful function variable
runningTotal = StatefulFunction()
# Use the stateful function
runningTotal(1)
# outputs: 1
runningTotal(5)
# outputs: 6
Another way to accomplish the same thing is with a Counter Dictionary
from collections import Counter
counter = Counter()
counter['runningTotal'] += 1
# in another part of the program
counter['runningTotal'] += 5
The output will be:
print(counter)
Counter({'runningTotal': 6})
Although there are ways of doing what you ask, it's not a good idea. As #JohnColeman pointed out, Simulate static variables in python with closures
But why not create a class?
class Accumulator:
total = 0
#classmethod
def add(cls, x):
cls.total += x
return cls.total
print(Accumulator.add(1))
print(Accumulator.add(2))
print(Accumulator.add(3))
Result:
1
3
6
You can set up a generator to maintain state and send values to it as well, as suggested by #HeapOverflow:
def get_running_total():
def _running_total():
value = 0
while True:
value += yield value
# get a generator instance
generator = _running_total()
# set it up to wait for input
next(generator)
# return the send method on the generator
return generator.send
# you can get a generator that functions similar to the Accumulator method
running_total = get_running_total()
print(running_total(1)) # prints 1
print(running_total(2)) # prints 3
print(running_total(3)) # prints 6
I believe this is a simple question but still want to get a quick and clear answer to my case:
def get_query_history(idx, url, archive_location):
idx = idx + 1
return idx # I meant to return the idx's value (end up 1000 for every call) and used it in the next loop in main
main:
idx = 1
while current <= end_date:
with open(archive_location, 'a') as the_archive:
get_query_history(idx, url, archive_location) # I want to increase the idx every time I call the function
Apparently this is not the way I should take in python, can anyone enlighten me?
Here, I'll post it as an answer but I'll expand a bit.
Since you're returning idx increased value, just store it back in the 'main' scope:
idx = 1
while current <= end_date:
with open(archive_location, 'a') as the_archive:
idx = get_query_history(idx, url, archive_location)
# make sure you update your `current` ;)
In some languages you have an option to pass a variable to a function by reference in such a way that the function can change its value so you wouldn't need to return your value. Python kind of passes by reference, but since simple values are unmutable whenever you try to set its value in your function the reference to the passed value gets overwritten.
This doesn't apply to encapsulated objects, tho, so you could encapsulate your idx in a list and then pass it as a list. In that case you wouldn't need return at all:
def get_query_history(idx, url, archive_location):
idx[0] += 1
# do whatever else
# in your main:
idx = [1] # encapsulate the value in a list
while current <= end_date:
with open(archive_location, 'a') as the_archive:
get_query_history(idx, url, archive_location) # notice, no return capture
# make sure you update your `current` ;)
But generally, if you can return the value there is no need for these shenanigans, it's just to demonstrate that a function can modify the passed arguments under certain conditions.
And, finally, if you really want to force pass-by-reference behavior, you can totally hack Python to do even that, check this (and never use it in production!) ;)
I want to summarize the following code. What it should do is check if the variable in the calculation is assigned. If not, then the result will be zero. Because I have hundreds of calculations like these I don't want to repeat the try-except for every calculation.
How could I do that?
a = 1
b = 2
d = 3
f = 2
try:
ab = a + b
except:
ab = 0
try:
ac = a - c
except:
ac = 0
try:
bg = b / g
except:
ac = 0
Write a function to do it, using a lambda (a one-line function) to defer the evaluation of the variables in case one of them doesn't exist:
def call_with_default(func, default):
try:
return func()
except NameError: # for names that don't exist
return default
ab = call_with_default(lambda: a+b, 0)
# etc.
You might benefit by using some sort of data structure (e.g. list or dictionary) to contain your values rather than storing them in individual variables; it's possible you could then use loops to do all these calculations instead of writing them all individually.
If you have a bunch of variables that might not even be defined, you probably don't really have a bunch of variables.
For example, if you're trying to build an interactive interpreter, where the user can create new variables, don't try to save each user variable as a global variable of the same name (if for no other reason than safety—what happens if the user tries to create a variable named main and erases your main function?). Store a dictionary of user variables.
Once you do that, the solutions suggested by Alexey and kindall will work:
def add_default(first, second, default):
try:
return variables[first] + variables[second]
except KeyError:
return default
variables['ab'] = add_default('a', 'b', 0)
If you really do need to mix in your code and user code at the same level, you can do it, by using globals() itself as your dictionary:
def add_default(first, second, default):
try:
return globals()[first] + globals()[second]
except KeyError:
return default
ab = add_default('a', 'b', 0)
However, using globals this way is almost always a sign that you've made a major design error earlier, and the right thing to do is back up until you find that error…
Meanwhile, from a comment:
I create a list of all my variables and loop through them if they have a value assigned or not. In case they have not I will set them to float('nan').
There's no way to create a list of variables (except, of course, by referencing them by name off globals()). You can create a list of values, but that won't do you any good, because there are no values for the undefined variables.
This is yet another sign that what you probably want here is not a bunch of separate variables, but a dictionary.
In particular, you probably want a defaultdict:
variables = collections.defaultdict(lambda: float('nan'))
For a more generic case you may use lambdas (though not too graceful solution):
def lambda_default(func, default, *args):
try:
return func(*args)
except:
return default
abc = lambda_default(lambda x, y: x + y * z, 0, a, b, c)
In case you have some commonly used functions, you may wrap them into one more def, of course:
def add_default(first, second, default):
return lambda_default(operator.add, 0, first, second)
ab = add_default(a, b, 0)