why don't we need to pass in a function as an argument for this decorator? - python-3.x

I have a decorator here which takes a number x as a input and multiplies it by the result of the function f_(*k). There is nothing wrong with the code it works perfectly. But the question is, when we use sq(n) how does this decorator take sq(n) and multiply it by 3? how does the decorator know to take the result of the function sq(n) and multiply it by 3. Because a parameter for a function was not given or in other words, how does it substitute f_(*k) for sq(n) because sq(n) was not given as an argument.
def multiply(x):
def multiply_x(f):
def f_(*k):
return x*f(*k)
return f_
return multiply_x
#multiply(3)
def sq(n):
return n*n

#decorator(arg) is just a nice way to say func = decorator(arg)(func)
When you pass in the argument to the decorator, you are returning a completely new function (multiply_x) as the return value from the decorator multiply and replacing the identifier sq with it.
This function you just returned then takes the original function sq which now becomes the f parameter inside the inner function.
Now when you do sq(n) you actually call the inner f_(n). This function returns x (the 3 you passed in as the argument to your decorator) times the result of calling the function f (which was the original sq function)
I hope this somewhat clears things up

Related

Does Python implement short-circuiting in built-in functions such as min()?

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.

What's wrong with my python recursive code?

Sorry for my ugly English.
This is one of my homework.
I'm making function that finds the max integer in any list, tuple, integer..
like "max_val((5, (1,2), [[1],[2]])) returns 5"
When I ran my code, there was no syntax error. I ran as many various cases I can.
But the homework system told me this code was incorrect.
Anyone give me hint?
numList = []
def max_val(t):
if type(t) is int:
numList.append(t)
else:
for i in range(len(t)):
if t[i] is int:
numList.append(t[i])
else:
max_val(t[i])
return max(numList)
Your code gives wrong results when called several times:
>>> max_val((5,4,3))
5
>>> max_val((2, 1))
5
That's because numList is a global variable that you don't "reset" between calls of your function.
You can simplify your code quite a bit, without needing that global variable:
def max_val(t):
if isinstance(t, int):
return t # t is the only element, so it's by definition the biggest
else:
# Assuming max_val works correctly for an element of t,
# return the largest result
return max(max_val(element) for element in t)
As explained in L3viathan's answer, the main issue with your code is that numList is a global variable. Here is a simple way to fix it without changing the logic of your code:
def max_val(t):
numList = [] # local variable
max_val_helper(t, numList) # fill numList with elements from t
return max(numList)
def max_val_helper(t, numList): # this function modifies its second argument and doesn't return a value
if type(t) is int:
numList.append(t)
else:
for i in range(len(t)):
max_val_helper(t[i], numList)
The function max_val_helper is recursive and appends all numbers in the nested iterables to its argument numList. This function doesn't have a return value; the effect of calling it is that it modifies its argument. This kind of function is sometimes called a "procedure".
The function max_val, on the other hand, is a "pure" function: it returns a value without any side-effect, like modifying its argument or a global variable. It creates a local variable numList, and passes this local variable to max_val_helper which fills it with the numberss from the nested iterables.
The code suggested in L3viathan's answer is arguably more elegant than this one, but I think it's important to understand why your code didn't work properly and how to fix it.
It's also good practice to differentiate between functions with side-effects (like modifying an argument, modifying a global variable, or calls to print) and functions without side-effects.

Is it possible to assign the value we return with "return" in the function to a value without calling the function itself?

def define():
a = input("Language:")
b = input("Version:")
return a,b
def print_language():
f = define()
print(f[0],f[1])
define()
print_language()
Language:Python
Version:3.8
Language:Python
Version:3.8
Python 3.8
The output of this is that it calls the function twice like this. I know the solution to this, only to call the 2nd function, but my question is:
Is it possible to assign the values we get from the first function with "return" to a variable, without calling the first function itself, and then, for example, when we send a value into the first function, can we call it and use it without repeating it a second time?
You need to pass the results of define() to print_language(), e.g.:
def print_language(f):
print(f[0],f[1])
result = define()
print_language(result)
Or this can be collapsed to:
print_language(define())

Python Function returning "function at" rather than numerical value

I want the below code to return a numerical value as opposed to <function exp at 0x101c22e18>:
def exp(x,y):
x**y
print(f"exp of {x} to the {y}")
return exp
test1 = 2
test2 = 2
testing = exp(test1, test2)
print(testing)
Why isn't my print statement returning 4?
If your intention is to output the value of x^y. You need to write
return x**y
Not return the function handle exp()
As Argyll has pointed out, the problem is in the function definition. Instead of:
def exp(x,y):
x**y
print(f"exp of {x} to the {y}")
return exp
you should write:
def exp(x,y):
result = str(x**y)
return print(f"{result} is the value of {str(x)} to the {str(y)}")
In your version, you just returned the function itself (and that's what you got: the function object ). In my version, you'd be returning the result of the function. You don't want the function back, you want what the function does back. And you want it back as a string which is why I've used the str() function: to convert integers and/or floats to their string equivalents.
Yes, you can return a function from a function--it's an "object" like any other--and there are many uses of this capability. In your case, though, you want the result of x**y back and not the function itself.
Note that the "f" formatting you used is only available in Python 3.6 or higher.

Two parameters in a predicate function

Is there a way that I can write a predicate function that will compare two strings and see which one is greater? Right now I have
def helper1(x, y):
return x > y
However, I'm trying to use the function in this way,
new_tuple = divide((helper1(some_value, l[0]),l[1:])
Please note that the above function call is probably wrong because my helper1 is incomplete. But the gist is I'm trying to compare two items to see if one's greater than the other, and the items are l[1:] to l[0]
Divide is a function that, given a predicate and a list, divides that list into a tuple that has two lists, based on what the predicate comes out as. Divide is very long, so I don't think I should post it on here.
So given that a predicate should only take one parameter, how should I write it so that it will take one parameter?
You should write a closure.
def helper(x):
def cmp(y):
return x > y
return cmp
...
new_tuple = divide(helper1(l[0]), l[1:])
...

Resources