Gere
Gere

Reputation: 12697

Python closure and function attributes

I tried to reimplement something like partial (which later will have more behavior). Now in the following example lazycall1 seems to work just as fine as lazycall2, so I don't understand why the documentation of partial suggests using the longer second version. Any suggestions? Can it get me in trouble?

def lazycall1(func, *args, **kwargs):
    def f():
        func(*args, **kwargs)
    return f

def lazycall2(func, *args, **kwargs):
    def f():
        func(*args, **kwargs)
    f.func=func   # why do I need that?
    f.args=args
    f.kwargs=kwargs
    return f

def A(x):
    print("A", x)

def B(x):
    print("B", x)

a1=lazycall1(A, 1)
b1=lazycall1(B, 2)
a1()
b1()

a2=lazycall2(A, 3)
b2=lazycall2(B, 4)
a2()
b2()

EDIT: Actually the answers given so far aren't quite right. Even with double arguments it would work. Is there another reason?

def lazycall(func, *args):
    def f(*args2):
        return func(*(args+args2))
    return f

def sum_up(a, b):
    return a+b

plusone=lazycall(sum_up, 1)
plustwo=lazycall(sum_up, 2)
print(plusone(6)) #7
print(plustwo(9)) #11

Upvotes: 3

Views: 773

Answers (3)

bigblind
bigblind

Reputation: 12867

The only extra thing the second form has, are some extra properties. This might be helpful if you start passing around the functions returned by lazycall2, so that the receiving function may make decisions based on these values.

Upvotes: 2

glyphobet
glyphobet

Reputation: 1562

Look closer at the argument names in the inner function newfunc in the Python documentation page you link to, they are different than those passed to the inner function, args vs. fargs, keywords vs. fkeywords. Their implementation of partial saves the arguments that the outer function was given and adds them to the arguments given to the inner function.

Since you reuse the exact same argument names in your inner function, the original arguments to the outer function won't be accessible in there.

As for setting func, args, and kwargs attributes on the outer function, a function is an object in Python, and you can set attributes on it. These attributes allow you to get access to the original function and arguments after you have passed them into your lazycall functions. So a1.func will be A and a1.args will be [1].

If you don't need to keep track of the original function and arguments, you should be fine with your lazycall1.

Upvotes: 0

AdamKG
AdamKG

Reputation: 14081

functools.partial can accept additional arguments - or overridden arguments - in the inner, returned function. Your inner f() functions don't, so there's no need for what you're doing in lazycall2. However, if you wanted to do something like this:

def sum(a, b):
    return a+b
plusone = lazycall3(sum, 1)
plusone(6) # 7

You'd need to do what is shown in those docs.

Upvotes: 0

Related Questions