Is it possible to define a closure for a function which is already defined?
For example I'd like to have a "raw" function and a function which already has some predefined values set by a surrounding closure.
Here is some code showing what I can do with a closure to add predefined variables to a function definition:
def outer(a, b, c):
def fun(d):
print(a + b + c - d)
return fun
foo = outer(4, 5, 6)
foo(10)
Now I want to have a definition of fun outside of a wrapping closure function, to be able to call fun either with variables from a closure or by passing variables directly. I know that I need to redefine a function to make it usable in a closure, thus I tried using lambda for it:
def fun(a, b, c, d): # raw function
print(a + b + c - d)
def clsr(func): # make a "closure" decorator
def wrap(*args):
return lambda *args: func(*args)
return wrap
foo = clsr(fun)(5, 6, 7) # make a closure with values already defined
foo(10) # raises TypeError: fun() missing 3 required positional arguments: 'a', 'b', and 'c'
fun(5, 6, 7, 10) # prints 8
What I also tried is using wraps from functools, but I was not able to make it work.
But is this even possible? And if yes: Is there any module which already implements decorators for this?
You can just define the wrap on the fly:
def fun(a, b, c, d): # raw function
print(a + b + c - d)
def closed(d): fun(5,6,7,d)
closed(10)
You can use this with lambda, but #juanpa points out you should not if there is no reason to. The above code will result in 8. This method by the way is not Python specific, most languages would support this.
But if you need a closure in a sense that it relies on the wrapper variables, than no, and there is good reason not to. This will create essentially a non-working function, that relies on wrapping. In this case using a class maybe better:
class fun:
def __init__(self,*args): #Can use specific things, not just *args.
self.args = args #Or meaningful names
def __call__(self,a, b, c, d): # raw function
print(a + b + c - d,self.args)
def closed(d):
fun("some",3,"more",['args'])(5,6,7,d)
closed(10)
or using *args/**kwargs directly and passing extra variables through that. Otherwise I am not familiar with a "inner function" construct that only works after wrapping.
Related
I have problem in understanding this code in Python
x = layers.Flatten()(last_output)
Since Flatten is a function, how does the function get the data from last_output written outside the function call parenthesis. Don't remember seeing this kind of code in Java.
Thanks and Regards
Flatten() is the class instantiation (which is probably clear to you) and the second calls the instance with that parameter. For this to work the class must have a __call__ function defined.
Example:
class Sum:
def __call__(self, a, b, c):
return a + b + c
s = Sum()
print(s(3, 4, 5))
print(Sum()(3,4,5))
Also same behavior can be obtained with a function that returns another function with arguments:
def Sum2():
def Sum3(a, b, c):
return a + b + c
return Sum3
s2 = Sum2()
print(s2(3, 4, 5))
print(Sum2()(3, 4, 5))
Consider this
def outer():
def print_thrice(string):
for _ in range(3):
print (string)
return print_thrice
If you call outer, it will return the print_thrice function which you can then call. So you'd use it like this
x = outer()
x("hello")
Or more compactly, outer()("hello") which is what's going on here.
Following is an example of what I would like to do.
def f(a, b, c):
if a == 'method1':
c = 0
return b + c
In this function, parameter c is unneeded if the condition a='method1' is satisfied.
Still, I can call the function with f(a='method1', b=1, c=2), which will have the same effect as f(a='method1', b=1, c=0).
A solution to this is to set the parameter c default to 0
def f(a, b, c=0):
if a == 'method1':
c = 0
return b + c
Now I can call f(a='method1',b=1), which is exactly what I want. The problem is, I can still change the parameter c in the call f(a='method1',b=1,c=1), which I do not want the user to be able to.
Can I enforce this condition in the function signature, and not in the body (i.e. I would not like to use if in the body). Or if there is another better solution, please tell.
Something like
def f(a, b, c = 0 if a == 'method1', else c is required):
return b + c
Thanks in advance.
a, b and c are all assigned dynamically at runtime. There is no way you can make up for this in the signature. It needs to be detected at runtime and you might as well do that in an if as anywhere else. You can specialize at the function name level, though, and python will take care of detecting the number of parameters.
def f(b,c):
return b + c
def f_method1(b):
return f(b, 0)
def f_method2(half_a_c):
return f(0, half_a_c*2)
Hmm... this almost seems like something that you should be able to do with functools.singledispatch and typing.Literal, but I can't quite get them to work together at least in python 3.7 (with Literal coming from the typing_extensions module). I think that in general singledispatch is probably the only tool that will really get what you've asked for as the different registered functions can have entirely different signatures. However, to do this our methods need to be different classes.
from functools import singledispatch
class Method1():
pass
class OtherMethods():
pass
#singledispatch
def f(method, b, c):
return b + c
#f.register(Method1)
def _(method, b):
return b
f(Method1(), 12) # returns 12
f(Method1(), 12, 7) # raises an error
f(OtherMethods(), 12) # raises an error
f(OtherMethods(), 12, 7) # returns 19
Now this is not exactly what you asked for but the arguments are enforced in the signature.
If someone who knows more about the implementation of singledispatch and Literal comes by maybe they can explain the interaction between the two.
One easier thing to do would be to simply define c to default to some invalid value.
def f(a, b, c=None):
if a == 'method1':
c = 0
return b + c
This solves the problem that if the user forgets to set c for a method besides method1 they'll receive a (possibly cryptic) error message. However it doesn't fix the fact that if they set c when using method1 that value will be silently ignored and possibly cause confusion.
I have this problem:
cons(a, b) constructs a pair, and car(pair) and cdr(pair) returns the first and last element of that pair. For example, car(cons(3, 4)) returns 3, and cdr(cons(3, 4)) returns 4.
Given this implementation of cons:
def cons(a, b):
def pair(f):
return f(a, b)
return pair
Implement car and cdr.
I don't get the function.
It has an inner function and calls an other function in the return. As far as I understood the inner functions is that these functions should depend on the functions above them. In this case on cons(..).
But the function is not using a or b. And why is the function f there? The task is to implement car and cdr, and function f should be given.
So could someone explain me this function? And how could I start with the task?
First of all: Python function objects are first class objects. A def statement results in a new function object, and you can retrieve that object by using the function name:
>>> def foo():
... return 'foo was called'
...
>>> foo
<function foo at 0x11b3d8ae8>
What this means is that you can assign that object to other names too, and you can pass them as parameters to function calls. You can then later on call the function object by adding (...) to the reference:
>>> bar = foo
>>> bar()
'foo was called'
The function name is assigned to in the current namespace. In a module, that's the globals, but in a function such as cons, the name is added as a local. return pair in the cons function then returns the function object pair to the caller.
And function parameters such as f and a and b are also variables; if you pass in a function object as a parameter, then parameter_name(...) will call paramater_name and pass in any arguments in the ... part. f(a, b) calls f and passes in a and b.
The next item to understand are closures; closures are an extra namespace attached to function objects, for variables from a surrounding scope.
In the following example, spam is a name in the closure of the bar function:
>>> def foo():
... spam = 'Vikings'
... def bar():
... return spam
... return bar
...
>>> foo()
<function foo.<locals>.bar at 0x11b44bf28>
>>> foo()()
'Vikings'
Calling foo() returns a new function object; the bar() function inside of foo(). Calling that returned function object produces 'Vikings', the value of the spam variable in the foo function. How did bar() get access to that? Via the closure:
>>> foo().__closure__
(<cell at 0x11b3c05b8: str object at 0x11b469180>,)
>>> foo().__closure__[0].cell_contents
'Vikings'
So nested functions can have access to names from the surrounding scope via closures. (Side note: it's not the value that's stored in a closure, it's the variable. The variable can change over time, and just like other variables accessing the name later will reflect the new value; if spam was changed later on, calling bar() again would return the new value).
Now to your function: cons() creates an inner function pair(), and pair() has access to the parameters a and b via its closure:
>>> def cons(a, b):
... def pair(f):
... return f(a, b)
... return pair
...
>>> cons(42, 81)
<function cons.<locals>.pair at 0x11b46f048>
>>> pair_42_81 = cons(42, 81)
>>> pair_42_81.__closure__
(<cell at 0x11b3c02b8: int object at 0x10f59a750>, <cell at 0x11b3c05b8: int object at 0x10f59ac30>)
>>> pair_42_81.__closure__[0].cell_contents
42
>>> pair_42_81.__closure__[1].cell_contents
81
The pair() function takes a parameter f, and calls that parameter, passing in a and b. Lets see what happens when we pass in print.
print is a function too, it is an object that you can call, and it writes the arguments to the console with spaces in between:
>>> print
<built-in function print>
>>> print('arg1', 'arg2')
arg1 arg2
If you passed that to the pair() function that cons() returns, you can see what f(a, b) does:
>>> pair_42_81(print)
42 81
print, passed to pair(), is assigned to f, and f(a, b) is exactly the same thing as print(a, b).
We can see that print() was called because the values are written out to the console. But you could also create a function that returns a new value. Say you have a function that adds up two numbers, and returns that value:
>>> def add(first, second):
... return first + second
...
>>> add(42, 81)
123
>>> pair_42_81(add)
123
We can call the function directly, and 123 is returned, or we can have pair_42_81() do it for us, and the same result is returned to us. Simple!
All this works because functions are objects and can be passed around like other variables, and because pair_42_81 has a = 42 and c = 81 stored in a closure, and will use those to call a given object f with those two arguments.
Next up are cdr() and car(), which will return either the first or last element of a pair. If cons(a, b) produces pair(f) returning f(a, b), then cdr() and car() must each create a function to pass to pair() that'll extract either a or b.
So create a nested function in each, and have cdr() and car() call pair() with that function. The nested function does the work of picking either a or b, and returns that value. Then return the result of the call to the outside world:
def car(pair):
def return_first(a, b):
return a
return pair(return_first)
def cdr(pair):
def return_last(a, b):
return b
return pair(return_last)
pair(return_first) calls return_first(a, b), a is returned, and car() can return that to the caller:
>>> car(cons(42, 81))
42
and the same applies to pair(return_last), only now b is returned:
>>> cdr(cons(42, 81))
81
You may be interested in the background of these operations; car, cdr and cons come from LISP, where cons a b Constructs a cell with two pointers (explaining the name), and car (meaning Contents of the Address part of the Register number in the IBM 704 instruction set LISP was created on) and cdr (meaning Contents of the Decrement part of the Register number in 704 language) take the first and remainder parts of such a cell. See this Wikipedia article on the names.
This is called a closure. Two basic elements
the pair function knows the values of a and b. They are just like local variables in that respect
the cons function returns a function, not a value. You have to call the result again
So, when you call cons(a, b) you get a function that does something to a and b, only it doesn't know what yet. You have to pass another function for that. Eg
my_f = cons(1, 2)
result = my_f(lambda x, y: x + y)
print(result) # 3
How this is related to your assignment is not very clear. I would only assume that for car, you only want the element a (the head), and for cdr you want the element b (the rest of the list). So, the functions would just return the one argument and ignore the other. Eg
car_f = lambda x, y: x
cdr_f = lambda x, y: y
cons is a function which takes two arguments, a and b and returns a function pair.
The function pair takes a function f as an argument which consumes two arguments.
def cons(a, b):
def pair(f):
return f(a, b)
return pair
f = lambda n, m: n**2 + m**3
car = lambda n, m: n
cdr = lambda n, m: m
print(cons(2, 3)(f))
print(cons(2, 3)(car))
print(cons(2, 3)(cdr))
f returns 31 = 2**2 + 3**3
Note how cons has two times the parenthesis (...) - once, for its own call and another time for the returned functions call.
Please note this answer to be able to call car(cons(2, 3)). You might also be interested in Why would a program use a closure?
I manually converted cons function the Javascript version and then implemented the quiz:
cons(a, b) constructs a pair, and car(pair) and cdr(pair) returns the first and last element of that pair. For example, car(cons(3, 4)) returns 3, and cdr(cons(3, 4)) returns 4.Given this implementation of cons:
def cons(a, b):
def pair(f):
return f(a, b)
return pair
Implement car and cdr.
Here is the solution
function cons(a, b) {
function pair(f) {
return f(a, b);
}
return pair;
}
function car(pair) {
return pair((a, b) => a);
};
function cdr(pair) {
return pair((a, b) => b);
};
console.log(car(cons(3,4)));
console.log(cdr(cons(3,4)));
Use lambda expressions
def cons(a, b):
def pair(f):
return f(a, b)
return pair
def car(pair):
return pair(lambda a, b: a)
def cdr(pair):
return pair(lambda a, b: b)
I've been having trouble understanding what h(a)(b) means. I'd never seen one of those before yesterday, and I couldn't declare a function this way:
def f (a)(b):
return a(b)
When I tried to do def f (a, b):, it didn't work either. What do these functions do? How can I declare them? And, finally, what's the difference between f(a, b)and f(a)(b)?
Functions with multiple parameter brackets don't exist, as you saw when you tried to define one. There are, however, functions which return (other) functions:
def func(a):
def func2(b):
return a + b
return func2
Now when you call func() it returns the inner func2 function:
>>> func2 = func(1) # You don't have to call it func2 here
>>> func2(2)
3
But if you don't need the inner function later on, then there's no need to save it into a variable and you can just call them one after the other:
>>> func(1)(2) # func(1) returns func2 which is then called with (2)
3
This is a very common idiom when defining decorators that take arguments.
Notice that calling func() always creates a new inner function, even though they're all named func2 inside of the definition of our func:
>>> f1 = func(1)
>>> f2 = func(1)
>>> f1(1), f2(1)
(2, 2)
>>> f1 is f2
False
And, finally, what's the difference between f(a, b)and f(a)(b)?
It should be clear now that you know what f(a)(b) does, but to summarize:
f(a, b) calls f with two parameters a and b
f(a)(b) calls f with one parameter a, which then returns another function, which is then called with one parameter b
f(a)(b) just means that the expression f(a) returns a value that is itself callable. It's a short form of
g = f(a)
g(b)
You might be more comfortable adding a pair of redundant parentheses to emphasize that this is not a single syntactic construct.
(f(a))(b) # f(a) is evaluated first, then the result is applied to b
It is exactly analogous to the same doubling of square brackets for indexing nested dictionaries.
d1[x][y]
is equivalent to
d2 = d1[x]
d2[y]
Lets say we have an expression like
f(a)(b)
then, f(a) returns a function itself which gets invoked with argument b. Consider the following example
def f(a):
def g(b):
return a * b
return g
Then f(5)(4) evaluates to 5 * 4, since f(5) returns a function which is basically
def g(b):
return 5 * b
One could now do stuff like this
mult_by_5 = f(5)
[mult_by_5(x) for x in range(10)]
Let's be fancy, what about more nested functions?:
def f(a):
def g(b):
def h(c):
return a * b *c
return h
return g
f(2)(3)(4) # 24
Lets say I have three functions in one module as defined below:
def add_nums(a, b):
return a + b
def sum_and_square_one(add_nums, a, b):
result = add_nums(a,b)
return result*result
def sum_and_square_two(a, b):
result = add_nums(a,b)
return result*result
Both functions sum_and_square_one and sum_and_square_two do the same task. But the former takes add_nums as an argument while the latter calls add_nums inside. My question is which one is the better way. Passing a function as an argument or calling inside a function?
If you always want to call the same function then there is no point in passing it as an argument every time. (this is the case in your example)
If you, however, want to dynamically call different (maybe similar) functions, then passing the appropiate function as an argument would make sense.
Depends on your use case. Do you need the function to change the way it works depending on that argument?
Or, rewriting your meaningless example into a bit less meaningless example (but still quite):
def add_nums(a, b):
return a + b
def do_something_then_square(a, b, what_to_do):
result = what_to_do(a, b)
return result * result
def sum_then_square(a, b):
result = add_nums(a, b)
return result * result
# Then you do:
sum_then_square(2, 5) # 49
do_something_then_square(2, 5, what_to_do=add_nums) # 49
do_something_then_square(2, 5, what_to_do=lambda a, b: a + b) # 49
do_something_then_square(2, 5, what_to_do=lambda a, b: a * b) # 100
do_something_then_square(2, 5, what_to_do=min) # 4
do_something_then_square(2, 5, what_to_do=complex) # (-21+20j)
Only question is: do you need that added flexibility? Otherwise it's just useless additional typing. That question must be answered on a case by case basis; it needs a complete example to give a useful answer.