0

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?

0

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

13 Comments

Yes, but please don't use lambda here. Just use a full function definition. The only advantage of lambda is that it can be anonymous, if you name your anonymous function it defeats the purpose of being anonymous.
@juanpa.arrivillaga I cannot say no to such a polite request.
It also happens to be proscribed by PEP8... :)
@juanpa.arrivillaga Polite, Elegant, Programmers?
Ohhh nooooo. Is it really that easy? Wow. I've been trying around for 2 hours. :D At least I got the part with the redefinition right... Thanks alot kabanus! :)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.