What Limitations Have Closures in Python Compared to Language X Closures

What limitations have closures in Python compared to language X closures?

The most important limitation, currently, is that you cannot assign to an outer-scope variable. In other words, closures are read-only:

>>> def outer(x): 
... def inner_reads():
... # Will return outer's 'x'.
... return x
... def inner_writes(y):
... # Will assign to a local 'x', not the outer 'x'
... x = y
... def inner_error(y):
... # Will produce an error: 'x' is local because of the assignment,
... # but we use it before it is assigned to.
... tmp = x
... x = y
... return tmp
... return inner_reads, inner_writes, inner_error
...
>>> inner_reads, inner_writes, inner_error = outer(5)
>>> inner_reads()
5
>>> inner_writes(10)
>>> inner_reads()
5
>>> inner_error(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in inner_error
UnboundLocalError: local variable 'x' referenced before assignment

A name that gets assigned to in a local scope (a function) is always local, unless declared otherwise. While there is the 'global' declaration to declare a variable global even when it is assigned to, there is no such declaration for enclosed variables -- yet. In Python 3.0, there is (will be) the 'nonlocal' declaration that does just that.

You can work around this limitation in the mean time by using a mutable container type:

>>> def outer(x):
... x = [x]
... def inner_reads():
... # Will return outer's x's first (and only) element.
... return x[0]
... def inner_writes(y):
... # Will look up outer's x, then mutate it.
... x[0] = y
... def inner_error(y):
... # Will now work, because 'x' is not assigned to, just referenced.
... tmp = x[0]
... x[0] = y
... return tmp
... return inner_reads, inner_writes, inner_error
...
>>> inner_reads, inner_writes, inner_error = outer(5)
>>> inner_reads()
5
>>> inner_writes(10)
>>> inner_reads()
10
>>> inner_error(15)
10
>>> inner_reads()
15

Can you explain closures (as they relate to Python)?

Closure on closures

Objects are data with methods
attached, closures are functions with
data attached.

def make_counter():
i = 0
def counter(): # counter() is a closure
nonlocal i
i += 1
return i
return counter

c1 = make_counter()
c2 = make_counter()

print (c1(), c1(), c2(), c2())
# -> 1 2 1 2

Python closure with side-effects

You can't do exactly that in Python 2.x, but you can use a trick to get the same effect: use a mutable object such as a list.

def closureMaker():
x = [0]
def closure():
x[0] += 1
print x[0]
return closure

You can also make x an object with a named attribute, or a dictionary. This can be more readable than a list, especially if you have more than one such variable to modify.

In Python 3.x, you just need to add nonlocal x to your inner function. This causes assignments to x to go to the outer scope.

Why aren't python nested functions called closures?

A closure occurs when a function has access to a local variable from an enclosing scope that has finished its execution.

def make_printer(msg):
def printer():
print(msg)
return printer

printer = make_printer('Foo!')
printer()

When make_printer is called, a new frame is put on the stack with the compiled code for the printer function as a constant and the value of msg as a local. It then creates and returns the function. Because the function printer references the msg variable, it is kept alive after the make_printer function has returned.

So, if your nested functions don't

  1. access variables that are local to enclosing scopes,
  2. do so when they are executed outside of that scope,

then they are not closures.

Here's an example of a nested function which is not a closure.

def make_printer(msg):
def printer(msg=msg):
print(msg)
return printer

printer = make_printer("Foo!")
printer() #Output: Foo!

Here, we are binding the value to the default value of a parameter. This occurs when the function printer is created and so no reference to the value of msg external to printer needs to be maintained after make_printer returns. msg is just a normal local variable of the function printer in this context.

Need help understanding Python closures

You can make i a function attribute

def doReplace(toReplace):
chapterReplacer.i = 1
def chapterReplacer(_):
result = 'Chapter %i' % chapterReplacer.i
chapterReplacer.i += 1
return result

return re.sub('Chapter [a-zA-Z]+', chapterReplacer, test)

EDIT: As of python 3, you can use nonlocal a la @MartijnPieters 's solution.

Python closure function losing outer variable access

When Python parses a function, it notes whenever it finds a variable used on the left-hand side of an assignment, such as

param1 = 'new'

It assumes that all such variables are local to the function.
So when you precede this assignment with

print param1

an error occurs because Python does not have a value for this local variable at the time the print statement is executed.


In Python3 you can fix this by declaring that param1 is nonlocal:

def with_wrapper(param1):
def dummy_wrapper(fn):
nonlocal param1
print param1
param1 = 'new'
fn(param1)
return dummy_wrapper

In Python2 you have to resort to a trick, such as passing param1 inside a list (or some other mutable object):

def with_wrapper(param1_list):
def dummy_wrapper(fn):
print param1_list[0]
param1_list[0] = 'new' # mutate the value inside the list
fn(param1_list[0])
return dummy_wrapper

def dummy():
@with_wrapper(['param1']) # <--- Note we pass a list here
def implementation(param2):
print param2

What is the difference between Swift Closures, Java Closures, and Python Lambda expressions?

A closure is a function that is defined in a way that allows it to carry values defined from another context, usually one of a "higher" scope.

The example you give above in Java is one. In Python, a lambda expression is not a closure. In Python, we would create a closure much like the Java example in your post. Here's an example of a Python closure:

def greet_boss(name):
def greet(person):
if person == name:
return "Yes sir!"
return f"Hello {name}"
return greet

greet_boss encloses greet and returns a function. Thus, you can do something like this: greet_boss("Obama")("Biden") and get "Hello Biden." But if you do greet_boss("Obama")("Obama") you get "Yes sir!".

Swift closures are also like that.

In Python, a lambda expression is an anonymous function. Lambda expressions define a callable, which works like a function, but it doesn't have a name. In Python, it is preferred only to use lambda expressions as parameters to higher order functions, like map and filter and other functions that take a callable as a parameter. Otherwise, you should probably just use a one line def func....

In functional programming languages functions are "first class citizens." This means that they can be passed around just like data (integers, strings, arrays, etc.) Not all languages treat functions this way. Some languages that are not strictly functional (e.g., Python) still have first class functions.
In the above examples, functions are returned by other functions: the return functions are closures. You can also pass functions as parameter values when they are first class. Example:

def return_certain_times(list_of_times, time_filter):
out = []
for time in list_of_times:
if time_filter(time):
out.append(time)
return out

If you have a list of days of the week, you can do something like return_certain_time(my_times, lambda x: x == "Saturday') and this would return a list of all the times that matched "Saturday". (This in not a great example of a function you would want, but it illustrates the concept pretty well.)

What limitations have closures in Python compared to language X closures?

The most important limitation, currently, is that you cannot assign to an outer-scope variable. In other words, closures are read-only:

>>> def outer(x): 
... def inner_reads():
... # Will return outer's 'x'.
... return x
... def inner_writes(y):
... # Will assign to a local 'x', not the outer 'x'
... x = y
... def inner_error(y):
... # Will produce an error: 'x' is local because of the assignment,
... # but we use it before it is assigned to.
... tmp = x
... x = y
... return tmp
... return inner_reads, inner_writes, inner_error
...
>>> inner_reads, inner_writes, inner_error = outer(5)
>>> inner_reads()
5
>>> inner_writes(10)
>>> inner_reads()
5
>>> inner_error(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in inner_error
UnboundLocalError: local variable 'x' referenced before assignment

A name that gets assigned to in a local scope (a function) is always local, unless declared otherwise. While there is the 'global' declaration to declare a variable global even when it is assigned to, there is no such declaration for enclosed variables -- yet. In Python 3.0, there is (will be) the 'nonlocal' declaration that does just that.

You can work around this limitation in the mean time by using a mutable container type:

>>> def outer(x):
... x = [x]
... def inner_reads():
... # Will return outer's x's first (and only) element.
... return x[0]
... def inner_writes(y):
... # Will look up outer's x, then mutate it.
... x[0] = y
... def inner_error(y):
... # Will now work, because 'x' is not assigned to, just referenced.
... tmp = x[0]
... x[0] = y
... return tmp
... return inner_reads, inner_writes, inner_error
...
>>> inner_reads, inner_writes, inner_error = outer(5)
>>> inner_reads()
5
>>> inner_writes(10)
>>> inner_reads()
10
>>> inner_error(15)
10
>>> inner_reads()
15


Related Topics



Leave a reply



Submit