47 votes

Quelles sont les limites ont des fermetures en Python par rapport à la langue X fermetures?

Où X est un langage de programmation (C#, Javascript, Lisp, Perl, Ruby, Scheme, etc) qui prend en charge certains saveur de fermetures.

Certaines limitations sont mentionnés dans les Fermetures en Python (par rapport à Ruby fermetures), mais l'article est vieux, et de nombreuses limitations n'existent pas dans moderne Python plus.

Voir un exemple de code pour un béton limitation serait génial.

Questions connexes:

44voto

Thomas Wouters Points 38811

La limitation la plus importante, actuellement, c'est que vous ne pouvez pas attribuer à l'extérieur de la portée de la variable. En d'autres termes, les fermetures sont en lecture seule:

>>> 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

Un nom qui sera affectée à une portée locale (une fonction) est toujours local, sauf déclaration contraire. Alors qu'il est le "global" déclaration pour déclarer une variable globale de même lorsqu'il est affecté, il n'y a pas une telle déclaration pour entre les variables -- encore. En Python 3.0, il est (sera) le 'non' de la déclaration qui fait exactement ça.

Vous pouvez contourner cette limitation dans le temps, à l'aide d'un mutable type de conteneur:

>>> 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

6voto

John Millikin Points 86775

La seule difficulté que j'ai vu des gens rencontre avec Python, en particulier, c'est quand ils essaient de mélanger des éléments non fonctionnels comme variable de réaffectation, avec des dispositifs de fermeture et sont surpris quand cela ne fonctionne pas:

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

Généralement simplement en indiquant qu'une fonction a ses propres variables locales est assez pour empêcher une telle bêtise.

6voto

mykhal Points 5873

Une limitation (ou "limitation") de Python fermetures, la comparant à Javascript fermetures, c'est qu'il ne peut pas être utilisée pour les données cacher

Javascript

var mksecretmaker = function(){
    var secrets = [];
    var mksecret = function() {
        secrets.push(Math.random())
    }
    return mksecret
}
var secretmaker = mksecretmaker();
secretmaker(); secretmaker()
// privately generated secret number list
// is practically inaccessible

Python

import random
def mksecretmaker():
    secrets = []
    def mksecret():
        secrets.append(random.random())
    return mksecret

secretmaker = mksecretmaker()
secretmaker(); secretmaker()
# "secrets" are easily accessible,
# it's difficult to hide something in Python:
secretmaker.__closure__[0].cell_contents # -> e.g. [0.680752847190161, 0.9068475951742101]

4voto

Kevin Little Points 5406

Fixe en Python 3 par l' nonlocal déclaration:

L' nonlocal instruction provoque la liste des identifiants pour consulter auparavant variables liées dans le plus proche du cadre englobant l'exclusion des variables globales. Ceci est important parce que le comportement par défaut pour la liaison est à la recherche de l'espace de noms local d'abord. La déclaration permet à encapsulé code pour relier les variables en dehors de la portée locale en plus de la global (module) champ d'application.

2voto

J.F. Sebastian Points 102961

@John Millikin

def outer():
    x = 1 # local to `outer()`

    def inner():
        x = 2     # local to `inner()`
        print(x)
        x = 3
        return x

    def inner2():
        nonlocal x
        print(x)  # local to `outer()`
        x = 4     # change `x`, it is not local to `inner2()`
        return x

    x = 5         # local to `outer()`
    return (inner, inner2)

for inner in outer():
    print(inner()) 

# -> 2 3 5 4

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X