I have a concept where I store function in variables which makes it easier for me. But I am having the problem that the value in the variable isn't dynamically calling the function each time. So it returns the same value all the time. Just to make clear of the problem, I have made a code snip to illustrate it in a easy way:
def value():
resp = requests.get('http://www.google.com').elapsed.total_seconds()
return resp
test = value()
while True:
print test
time.sleep(10)
Output:
0.00649
0.00649
In this case, in the while true
when I print test, it returns the same value, even though I am calling the function value()
. How can I solve this issue? I know I can put the function in the while loop, but I want to have it as a variable.
The previous answers are correct, but please let me elaborate.
In the world of Python, things have very precise meanings but it's not always clear what is what if you are just getting started.
Expressions are things that have a value, and they include things like 123
, some_variable
and 10 / 2
. The name some_variable
is called an identifier, simply because it identifies a value. Just like the name Scruffy might identify your dog.
Statements are things that affect the program flow or the state of your program, but lack a value. The following are examples of statements:
if x > 10:
x -= 1
And
def foo(x):
print("The value of x is", x)
Unlike in JavaScript, for example, where almost everything is an expression (and has a value), you can not do this:
my_function = def foo(x): print("The value of x is", x)
The previous def
statement will create a function by the name foo
, but the statement itself doesn't have a value. The name foo
will refer to a value, however. It means that when you write foo
, the value will be a thing, and this thing is a function!
The expression x()
on the other hand will do two things. First it will look up the value of the identifier x
. Hopefully this value is a function. After that, the parentheses means that the value will be called. What happens if x
is not a function, then?
>>> x = 10
>>> x()
Traceback (most recent call last):
File "<ipython-input-3-7354d77c61ac>", line 1, in <module>
x()
TypeError: 'int' object is not callable
Big Fat Error: 10 is not a "callable". Callable means something that can be called like a function.
The parentheses are, as you probably know, a list of arguments. In this case the list is simply empty so when you write x()
you are saying "call whatever the name 'x' is referring to but don't send any arguments".
A function call always has a value, since it's an expression. If you don't explicitly return anything, the value will simply be None
.
To answer your question, finally, let's play the substitution game. The rules are simple, any expression can be replaced by its value:
def value():
resp = requests.get('http://www.google.com').elapsed.total_seconds()
return resp
This is a statement, so it doesn't have a value. A function is created with the name value
, however.
The function consists of two statements (no value, again), a variable assignment and a return statement.
The thing to the right of the =
is an expression however. Short story:
requests
is referring to the requests moduleget
is referring to a module-global function in the above moduleget('...')
is calling this function, and something is returned.elapsed
, which has a property called total_seconds
.total_seconds
is an identifier that refers to a callable. The callable is called without any arguments (total_seconds()
) and something is returned. Probably a number, based on the name. Let's say its value is always 10
, for simplicity.The next statement is another assignment:
test = value()
This can be thought of as "let the name 'test' refer to the value that is returned by the callable identified by the name 'value' when it is called with an empty argument list". In our case, the function object called value
will be called, resp
will be assigned the value 10
, then the return
statement will let the caller know that this call is sending the value 10
back. The name test
will refer to the value 10
, from now on.
Let's go over the loop, quickly:
while True:
print test
time.sleep(10)
Do the following until the end of Time:
print
(a statement in Python 2, an expression in Python 3!) has the side-effect of printing stuff to the screen. Otherwise it doesn't do much.test
is. We already know that the identifier test
is referring to the value 10
. It will simply print "10" to the screen.You probably want to invoke some function at each iteration of the loop ("invoke" is basically latin for "call", I like fancy words). Otherwise the program will just print "10", "10", "10", over and over again. To fix this this, you first have to change the expression evaluated as part of the print
statement from just an identifier (test
) to a function call:
print test()
But this will, as we saw before, raise a Big Fat Error since 10
is not a callable function. To fix it (that's what programmers do, right?) you also need to change the value of test
from 10
, since it's not a callable, to the function. A function can be referred to simply by its name, so just change this line:
test = value() # equals ten
To this:
test = value # equals the function called "value"
The function now has two names, the old name "value", and the new name "test". Each step in the loop will request the page again and return the new time it took for the request to complete. If the request times out you will have a different kind of crash, but that's another story.
Further information can be found in the Python Language Reference.