Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Where X is any programming language (C#, Javascript, Lisp, Perl, Ruby, Scheme, etc) which supports some flavour of closures.

Some limitations are mentioned in the Closures in Python (compared to Ruby's closures), but the article is old and many limitations do not exist in modern Python any more.

Seeing a code example for a concrete limitation would be great.

Related questions:

  • Can you explain closures (as they relate to Python)?
  • What is a ‘Closure’?
  • How does a javascript closure work ?
like image 847
jfs Avatar asked Sep 26 '08 20:09

jfs


People also ask

What are the advantages of closures in Python?

ADVANTAGE : Closures can avoid use of global variables and provides some form of data hiding. (Eg. When there are few methods in a class, use closures instead). Also, Decorators in Python make extensive use of closures.

What is the difference between decorators and closures?

A decorator is a function that takes in a function and returns an augmented copy of that function. When writing closures and decorators, you must keep the scope of each function in mind. In Python, functions define scope. Closures have access to the scope of the function that returns them; the decorator's scope.

What is closure in Python stackoverflow?

In Python, a closure is an instance of a function that has variables bound to it immutably. In fact, the data model explains this in its description of functions' __closure__ attribute: None or a tuple of cells that contain bindings for the function's free variables. Read-only.


2 Answers

The only difficulty I've seen people encounter with Python's in particular is when they try to mix non-functional features like variable reassignment with closures, and are surprised when this doesn't work:

def outer ():     x = 1     def inner ():         print x         x = 2     return inner outer () () 

Usually just pointing out that a function has its own local variables is enough to deter such silliness.

like image 33
John Millikin Avatar answered Oct 11 '22 05:10

John Millikin


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 
like image 78
Thomas Wouters Avatar answered Oct 11 '22 05:10

Thomas Wouters