I have a question regarding a tutorial problem.
Write a function make_monitored that takes as input a function, f, that itself takes one input. The result returned by make_monitored is a third function, say mf, that keeps track of the number of times it has been called by maintaining an internal counter. If the input to mf is the special string "how-many-calls?", then mf returns the value of the counter. If the input is the special string "reset-count", then mf resets the counter to zero. For any other input, mf returns the result of calling f on that input and increments the counter.
I have the following solution which works, surprisingly.
def make_monitored(f):
calls=[0]
def helper(n):
if n=="how-many-calls?":
return calls[0]
elif n=="reset-count":
calls[0]=0
else:
calls[0]+=1
return f(n)
return helper
I recalled reading about UnboundLocalError here: UnboundLocalError in Python
My question would be why won't calls[0]+=1 trigger that error? I made an assignation to a variable outside the local scope of the third function helper , and it seems a similar solution that uses instead calls.append(1) (the rest of the code correspondingly becomes len(calls) and calls.clear()) also bypasses that error.
Related
Does Python 3 implement short-circuiting in built-in functions whenever possible, just like it does for boolean statements?
A specific example, take the below code snippet:
min((20,11), key = lambda x : x % 10) # 20
Does Python evaluate beforehand that the minimum value possible of the function passed as the key argument is 0, and therefore stops right after evaluating the first integer in the iterable passed (20) as 20 % 10 is equal to 0?
Or does it have to evaluate all the elements in the iterable before returning the answer?
I guess short-circuiting isn't even always possible especially for more complex functions, but what about for well-known, built-in functions or operators like %?
I couldn't find the answer in the official docs.
Thanks,
python has to evaluate all values inside the iterable because the languaje evaluate element by element, if you have in your tuple something that is not a number it will trigger an exception when try to perform the % operation. Python can not guess what is inside your list. You can test this by defining a function instead of a lambda and set debug point inside.
def my_mod(x):
import ipdb; ipdb.set_trace()
return x % 20
then call the function
min((20,11), key = my_mod)
you can do a quick error test case with
min((20,11, "s"), key = my_mod)
It will trigger an exception but first had to evaluate all the previous element in the list.
Whenever I am trying to run the given code it always gives the error 'str' object is not callable.
Somebody please tell me what is wrong with the code.
Here is the code:
def intel():
c=0
for i in num(1,9):
if((num[i]%2)==0):
c=c+1
return c
num = input()
out= intel()
print(out)```
Bachchu, welcome! There are a few different things going on here:
As usr2564301 explained, the TypeError: 'str' object is not callable is Traceback for statement for i in num(1,9): because the num() function does not exist unless you define one yourself. That is to say that functions like print() are built-in to Python such that you need not import additional modules to have automatic access to them. The num() function does not exist in the default 'namespace' which you have access to. Perhaps you did define one in another module and forgot to import it, or perhaps you did not mean to call that as a function, but it caused the error because unless you have visibility to it (for example through a def or import) then it does not exist as far as Python is concerned.
This segues into Carl Brubaker's assumption that you meant to use the range() function instead of num() altogether. The range() function would generate a list of [1,2,3,4,5,6,7,8] for your code to iterate through. It starts at the first argument (1) and goes up to but not including the second argument (9-1 = 8). I will add that perhaps, if you did indeed intend for the generation of a list, you probably meant to include 9 in the list, in which case you would need to use range(1,10).
As far as num() and input() are concerned, I don't think you are trying to define a num() function by entering it at the keyboard and assigning it to variable num via a call to the input() function.
The num = input() statement accepts user input from the keyboard and assigns it in string format to the variable num. As Carl Brubaker explained, you will need to convert (or cast if you are familiar with other languages) that data to int() before comparing it numerically. You can easily do this by wrapping the input() call:
num = int(input())
or like this:
num = input()
num = int(num)
One last piece of two-cents: The input() function can be passed a prompt string to present to the user so that when the control is passed to the terminal, the prompt will indicate to the user that it is expecting something. Here's an example:
num = int(input('Please enter a number: '))
As expected, this will present the user, at the terminal (command prompt), with the following:
Please enter a number:
Note that the blank space is a spacer so that the user's data will begin one space after the colon (for the sake of clarity).
At this juncture, we could guess what your objective is, but it would be best if you first cleaned up what we have pointed out here, then followup with outstanding issues, if any remain.
Let´s say I have 2 functions like these ones:
def list(n):
l=[x for x in range(n)]
return l
def square(l):
l=list(map(lambda x:x**2,l))
print(l)
The first one makes a list from all numbers in a given range which is "n" and the second one receives a list as a parameter and returns the squared values of this list.
However when I write:
square(list(20))
it raises the error "map object cannot be interpreted as an integer" and whenever I erase one of the functions above and run the other one it runs perfectly and I have no idea what mistake I made.
You redefined the standard function list()! Rename it to my_list() and clean the code accordingly.
As a side note, your function list() is doing exactly what list(range(n)) would do. Why do you need it at all? In fact, for most purposes (including your example), range(n) alone is sufficient.
Finally, you do not pass a function as a parameter. You pass the value generated by another function. It is not the same.
I am getting an value from the user in getInteger.
I need to get the output from sqInteger in getInteger.
No matter how I set up the parameters or indent the sqInteger function, variable x is undefined.
I added a return line to try and pass the x variable, but that's definitely not helping.
Please help me understand what I'm missing!
def getInteger():
while True:
try:
x = int(input('Enter an integer: '))
except ValueError:
print()
print('That\'s not an integer. Try again.')
continue
else:
return x
print(x)
break
def sqInteger(getInteger, x):
y = x**2
print(y)
Is this the entire code? You need to call the getInteger() function at some point in the code before that loop will begin. You're also not calling function sqInteger() at any point.
Your exception handler will immediately stop evaluating the try block and move down to the except block upon a non-integer being typed into the input. Therefore, you can place a call to the sqInteger() function after the input() function. If the user types a non-integer into the terminal, it will move down to your Exception handler and prompt the user to retry. If they enter an integer, the code will continue to evaluate and run the function sqInteger.
For this, you also do not need to pass getInteger into the sqInteger() function. You are technically allowed to pass functions as parameters in Python but it's not necessary for this and probably out of the scope of this program.
So the following code would be suitable:
def getInteger():
while True:
try:
x = int(input('Enter an integer: '))
# variable 'squared' now receives the return value from the function
squared = sqInteger(x) # call to function sqInteger necessary for this function to be executed
except ValueError:
print('That\'s not an integer. Try again.')
continue
else:
print(x) # if user entered 2, prints 2, not 4
return x # this value is still only what the user input, not the result of sqInteger()
break
def sqInteger(x):
y = x**2
print(y)
return y #you need to return values from functions in order to access it from outside the function
The reason you pass a variable into a function (as a parameter) is to give that function access to that variable. Creating a function creates a local scope for that function so that variables named within that function are in a separate namespace from variables outside that function. This is useful in large programs where many variables might exist and you need to keep them separate.
Because you've separately defined a sqrt function, it does not have access to variables outside of its scope. You need to pass in variables that you'd like it to have access to.
You also need to call functions before they will run. Defining a function only serves to set up the function so that it can be called as one functional unit. It's useful for separating concerns within a program. The ability to call a function is useful because it allows you to separate your code out and only mention a single call to a function rather than having the entire functionality jumbled in with the rest of the code. It also allows for reusability of code.
You can also have access to the result of the squared integer by returning a value and assigning this value to a function call, like such:
# lets say x = 4
squared = sqInteger(x)
def sqInteger(x):
y = x**2
return y
This would NOT work:
x = input("Enter integer") #lets say you enter 3
squared = sqInteger()
print(squared)
def sqInteger():
print(x) # error: x is not defined
return x**2 # error: x is not defined
The function does not have access to outside variables like x. It must be passed these variables as parameters so that you can call this function and set the parameters at will. This is for the sake of modularity in a program. You can pass it all sorts of different integers as parameters and it allows you to have a resuable function for anytime you need to square an integer.
Edit: Sorry this was a mess, I finally fixed all the errors in my explanation though...
I am interested in creating a list / array of functions "G" consisting of many small functions "g". This essentially should correspond to a series of functions 'evolving' in time.
Each "g" takes-in two variables and returns the product of these variables with an outside global variable indexed at the same time-step.
Assume obs_mat (T x 1) is a pre-defined global array, and t corresponds to the time-steps
G = []
for t in range(T):
# tried declaring obs here too.
def g(current_state, observation_noise):
obs = obs_mat[t]
return current_state * observation_noise * obs
G.append(g)
Unfortunately when I test the resultant functions, they do not seem to pick up on the difference in the obs time-varying constant i.e. (Got G[0](100,100) same as G[5](100,100)). I tried playing around with the scope of obs but without much luck. Would anyone be able to help guide me in the right direction?
This is a common "gotcha" to referencing variables from an outer scope when in an inner function. The outer variable is looked up when the inner function is run, not when the inner function is defined (so all versions of the function see the variable's last value). For each function to see a different value, you either need to make sure they're looking in separate namespaces, or you need to bind the value to a default parameter of the inner function.
Here's an approach that uses an extra namespace:
def make_func(x):
def func(a, b):
return a*b*x
return func
list_of_funcs = [make_func(i) for i in range(10)]
Each inner function func has access to the x parameter in the enclosing make_func function. Since they're all created by separate calls to make_func, they each see separate namespaces with different x values.
Here's the other approach that uses a default argument (with functions created by a lambda expression):
list_of_funcs = [lambda a, b, x=i: a*b*x for i in range(10)]
In this version, the i variable from the list comprehension is bound to the default value of the x parameter in the lambda expression. This binding means that the functions wont care about the value of i changing later on. The downside to this solution is that any code that accidentally calls one of the functions with three arguments instead of two may work without an exception (perhaps with odd results).
The problem you are running into is one of scoping. Function bodies aren't evaluated until the fuction is actually called, so the functions you have there will use whatever is the current value of the variable within their scope at time of evaluation (which means they'll have the same t if you call them all after the for-loop has ended)
In order to see the value that you would like, you'd need to immediately call the function and save the result.
I'm not really sure why you're using an array of functions. Perhaps what you're trying to do is map a partial function across the time series, something like the following?
from functools import partial
def g(current_state, observation_noise, t):
obs = obs_mat[t]
return current_state * observation_noise * obs
g_maker = partial(g, current, observation)
results = list(map(g_maker, range(T)))
What's happening here is that partial creates a partially-applied function, which is merely waiting for its final value to be evaluated. That final value is dynamic (but the first two are fixed in this example), so mapping that partially-applied function over a range of values gets you answers for each value.
Honestly, this is a guess because it's hard to see what else you are trying to do with this data and it's hard to see what you're trying to achieve with the array of functions (and there are certainly other ways to do this).
The issue (assuming that your G.append call is mis-indented) is simply that the name t is mutated when you loop over the iterator returned by range(T). Since every function g you create stores returns the same name t, they wind up all returning the same value, T - 1. The fix is to de-reference the name (the simplest way to do this is by sending t into your function as a default value for an argument in g's argument list):
G = []
for t in range(T):
def g(current_state, observation_noise, t_kw=t):
obs = obs_mat[t_kw]
return current_state * observation_noise * obs
G.append(g)
This works because it creates another name that points at the value that t references during that iteration of the loop (you could still use t rather than t_kw and it would still just work because tg is bound to the value that tf is bound to - the value never changes, but tf is bound to another value on the next iteration, while tg still points at the "original" value.