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
- access variables that are local to enclosing scopes,
- 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
Django Submit Two Different Forms with One Submit Button
Why Are Str.Count('') and Len(Str) Giving Different Output
Convert Row to Column Header for Pandas Dataframe,
Python Pip Specify a Library Directory and an Include Directory
How to Create a Datetime in Python from Milliseconds
Python How to Write to a Binary File
Best Way to Create a "Reversed" List in Python
Checking If All Elements in a List Are Unique
Python Read JSON File and Modify
How to Make Urllib2 Requests Through Tor in Python
Split a String to Even Sized Chunks
How to Move Pandas Data from Index to Column After Multiple Groupby
Why Don't Methods Have Reference Equality
Count Unique Values Using Pandas Groupby
How to Change the Range of the X-Axis with Datetimes in Matplotlib
How to Specify an Authenticated Proxy for a Python Http Connection