Pregunta

He estado leyendo mucho acerca de los cierres y creo que los entiendo, pero sin que nubla la imagen para mí y para los demás, estoy esperando que alguien puede explicar los cierres como de manera sucinta y clara como sea posible.Estoy buscando una explicación simple que me puede ayudar a entender dónde y por qué me desea utilizar.

¿Fue útil?

Solución

Cierre en los cierres

Los objetos son los datos con los métodos de adjunto, los cierres son funciones con datos adjuntos.

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

Otros consejos

Es muy sencillo:Una función que hace referencia a las variables del ámbito de contenido, potencialmente después de que el flujo de control a la izquierda de ese ámbito.Esa última parte es muy útil:

>>> def makeConstantAdder(x):
...     constant = x
...     def adder(y):
...         return y + constant
...     return adder
... 
>>> f = makeConstantAdder(12)
>>> f(3)
15
>>> g = makeConstantAdder(4)
>>> g(3)
7

Tenga en cuenta que 12 y 4 han "desaparecido" en el interior de f y g, respectivamente, esta característica es lo que hace a f y g adecuada de los cierres.

Me gusta este áspero, sucinta definición:

Una función que puede referirse a entornos en los que ya no están activos.

Me gustaría añadir

Un cierre permite enlazar las variables en una función sin pasarlos como parámetros.

Decoradores que aceptar los parámetros son de uso común para los cierres.Los cierres son comunes en la implementación de un mecanismo de ese tipo de "función"de fábrica.Me suelen optar por el uso de cierres en el El Modelo De Estrategia cuando la estrategia se modifica datos en tiempo de ejecución.

En un lenguaje que permite anónimo definición de bloque-por ejemplo, Ruby, C# -- cierres pueden ser utilizados para implementar (qué cantidad) de la novela de nuevas estructuras de control.La falta de bloques anónimos es entre las limitaciones de los cierres en Python.

Para ser honesto, yo entiendo cierres perfectamente bien, excepto yo nunca he sido claro acerca de qué es exactamente lo que es el "cierre" ¿y qué tiene de "cierre" al respecto.Yo recomiendo que usted da para arriba en busca de cualquier lógica detrás de la elección de plazo.

De todos modos, aquí va mi explicación:

def foo():
   x = 3
   def bar():
      print x
   x = 5
   return bar

bar = foo()
bar()   # print 5

Una idea clave aquí es que el objeto de la función regresó de foo conserva un gancho para el local var ('x' aunque 'x' ha salido del ámbito y debe ser desaparecida.Este gancho es el var en sí, no sólo el valor que var había en el momento, así que cuando la barra se llama, se imprime 5, no 3.

También quedar claro que Python 2.x ha limitado cierre:no hay manera de que yo pueda modificar 'x' dentro de 'bar' porque 'de la escritura x = bla' sería declarar un local de 'x' en la barra, no ceder a la 'x' de foo.Este es un efecto secundario de Python asignación=declaración.Para evitar esto, Python 3.0 introduce el no locales de palabras clave:

def foo():
   x = 3
   def bar():
      print x
   def ack():
      nonlocal x
      x = 7
   x = 5
   return (bar, ack)

bar, ack = foo()
ack()   # modify x of the call to foo
bar()   # print 7

Nunca he oído hablar de las transacciones que se utiliza en el mismo contexto como explicar lo que un cierre y no hay realmente ninguna transacción semántica de aquí.

Se llama un cierre porque se "cierra" el fuera de la variable (constante)--es decir, no es sólo una función, pero en un recinto de el entorno en el que la función se ha creado.

En el siguiente ejemplo, una llamada al cierre g después de cambiar x también cambiará el valor de x en g, ya que g se cierra sobre x:

x = 0

def f():
    def g(): 
        return x * 2
    return g


closure = f()
print(closure()) # 0
x = 2
print(closure()) # 4

He aquí un caso de uso típico para el cierre de las incidencias de los elementos de la GUI (esta sería una alternativa para crear subclases de la clase button).Por ejemplo, usted puede construir una función que será llamada en respuesta a una pulsación de un botón, y "cerrar" sobre las variables relevantes en el ámbito primario que son necesarios para el procesamiento de la haga clic en.De esta manera usted puede transferir bastante complicadas interfaces de la misma función de inicialización, la construcción de todas las dependencias en el cierre.

En Python, un cierre es un ejemplo de una función que tiene las variables unida a ella, inmutable.

De hecho, la modelo de datos se explica esto en su descripción de funciones' __closure__ atributo:

Ninguno o un tupla de células que contienen enlaces para la función de variables libres.Sólo lectura

Para demostrar esto:

def enclosure(foo):
    def closure(bar):
        print(foo, bar)
    return closure

closure_instance = enclosure('foo')

Claramente, sabemos que ahora tenemos una función señalada en el nombre de la variable closure_instance.Aparentemente, si lo llamamos con un objeto, bar, se debe imprimir la cadena, 'foo' y sea cual sea la representación de cadena de bar es.

De hecho, la cadena 'foo' es enlazado a la instancia de la función, y se puede leer directamente aquí, accediendo a la cell_contents atributo de la primera (y única) de la célula en la tupla de la __closure__ atributo:

>>> closure_instance.__closure__[0].cell_contents
'foo'

Por otro lado, las células de los objetos son descritos en la documentación de la API de C:

"La celda" objetos se utilizan para implementar las variables que se hace referencia por varios los ámbitos de

Y podemos demostrar nuestro cierre de uso, señalando que 'foo' está atascado en la función y no cambia:

>>> closure_instance('bar')
foo bar
>>> closure_instance('baz')
foo baz
>>> closure_instance('quux')
foo quux

Y nada puede cambiarlo:

>>> closure_instance.__closure__ = None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: readonly attribute

Funciones Parciales

El ejemplo utiliza el cierre, como una función parcial, pero si este es nuestro único objetivo, el mismo objetivo se puede lograr con functools.partial

>>> from __future__ import print_function # use this if you're in Python 2.
>>> partial_function = functools.partial(print, 'foo')
>>> partial_function('bar')
foo bar
>>> partial_function('baz')
foo baz
>>> partial_function('quux')
foo quux

Hay más complicada cierres así que no se ajuste a la función parcial ejemplo, y voy a demostrar lo permita el tiempo.

Aquí es un ejemplo de Python3 cierres

def closure(x):
    def counter():
        nonlocal x
        x += 1
        return x
    return counter;

counter1 = closure(100);
counter2 = closure(200);

print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 2 " + str(counter2()))
print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 1 " + str(counter1()))
print("i from closure 2 " + str(counter2()))

# result

i from closure 1 101
i from closure 1 102
i from closure 2 201
i from closure 1 103
i from closure 1 104
i from closure 1 105
i from closure 2 202
# A Closure is a function object that remembers values in enclosing scopes even if they are not present in memory.

# Defining a closure

# This is an outer function.
def outer_function(message):
    # This is an inner nested function.
    def inner_function():
        print(message)
    return inner_function

# Now lets call the outer function and return value bound to name 'temp'
temp = outer_function("Hello")
# On calling temp, 'message' will be still be remembered although we had finished executing outer_function()
temp()
# Technique by which some data('message') that remembers values in enclosing scopes 
# even if they are not present in memory is called closures

# Output: Hello

Los criterios a cumplir por los Cierres son:

  1. Debemos tener una función anidada.
  2. Función anidada debe referirse al valor definido en el bloque dentro de la función.
  3. Que encierra la función debe devolver la función anidada.

# Example 2
def make_multiplier_of(n): # Outer function
    def multiplier(x): # Inner nested function
        return x * n
    return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
print(times5(3)) # 15
print(times3(2)) #  6

Para mí, "cierres" son funciones que son capaces de recordar el entorno en el que fueron creados.Esta funcionalidad, que permite el uso de variables o métodos dentro de la clausura que, de otra manera,usted no será capaz de utilizar ya sea porque no existe o que están fuera de su alcance debido a su alcance.Veamos este código en ruby:

def makefunction (x)
  def multiply (a,b)
    puts a*b
  end
  return lambda {|n| multiply(n,x)} # => returning a closure
end

func = makefunction(2) # => we capture the closure
func.call(6)    # => Result equal "12"  

funciona incluso cuando ambos, "multiplicar" el método y la "x" variable deja de existir.Todo porque el cierre de la capacidad de recordar.

todos hemos utilizado Decoradores en python.Son buenos ejemplos para mostrar lo que están cierre funciones en python.

class Test():
    def decorator(func):
        def wrapper(*args):
            b = args[1] + 5
            return func(b)
        return wrapper

@decorator
def foo(val):
    print val + 2

obj = Test()
obj.foo(5)

aquí el valor final es de 12

Aquí, la función de contenedor es capaz de acceder a func objeto porque el envoltorio es "léxico de cierre", se puede acceder a los atributos primarios.Por eso, es capaz de acceder a func objeto.

Me gustaría compartir mi ejemplo y una explicación acerca de los cierres.Hice un python ejemplo, y dos cifras para demostrar la pila de los estados.

def maker(a, b, n):
    margin_top = 2
    padding = 4
    def message(msg):
        print('\n’ * margin_top, a * n, 
            ' ‘ * padding, msg, ' ‘ * padding, b * n)
    return message

f = maker('*', '#', 5)
g = maker('', '♥’, 3)
…
f('hello')
g(‘good bye!')

La salida de este código sería el siguiente:

*****      hello      #####

      good bye!    ♥♥♥

Aquí hay dos figuras para mostrar las pilas y el cierre se adjunta a la función de objeto.

cuando la función devuelve maker

cuando la función es llamada más tarde

Cuando se llama a la función a través de un parámetro o un no local variable, el código necesidades locales ligaduras de variables tales como margin_top, relleno, así como la a, b, n.Con el fin de garantizar la función de código de trabajo, el marco de pila de la persona, la función que estaba desaparecido hace mucho tiempo, debería ser accesible, que está respaldada en el cierre podemos encontrar junto con el mensaje de la función del objeto.

La mejor explicación que he visto de un cierre fue para explicar el mecanismo.Fue algo como esto:

Imagine que su programa de pila como un degenerado árbol donde cada nodo sólo tiene un hijo y el único nodo hoja es el contexto del que se está ejecutando actualmente procedimiento.

Ahora relajar la restricción de que cada nodo sólo puede tener un hijo.

Si usted hace esto, usted puede tener un constructo ("cosecha") que puede volver de un procedimiento, sin descartar el contexto local (es decir,no pop fuera de la pila cuando regrese).La próxima vez que el procedimiento se invoca, la invocación recoge la antigua pila (árbol) marco y continúa la ejecución de donde salió.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top