example - run function inside function python




¿Qué es exactamente lo que está contenido dentro de un cierre obj.__? (3)

Es el nuevo nombre de Python 3 para el antiguo func_closure .

http://docs.python.org/3.0/whatsnew/3.0.html

Los atributos de función llamados func_X han sido renombrados para usar el formulario __X__ , liberando estos nombres en el espacio de nombres de atributo de función para los atributos definidos por el usuario. Para func_closure , func_code func_closure , func_code , func_defaults , func_dict , func_doc , func_globals , func_name a __closure__ , __code__ , __defaults__ , __dict__ , __doc__ , __globals__ , __name__ , respectivamente.

En una palabra:

__closure__ es None o una tuple de celdas que contienen enlaces para las variables libres de la función.

Además, NO es escribible.

Referencia: http://docs.python.org/ref/types.html

Ejemplo Python <3 (entonces estoy usando func_closure )

def foo():
    x = "I am used"
    y = "I am free"
    z = "I am free too"

    def bar(x):
        return x, y, z

    return bar

c = foo().func_closure

print [i.cell_contents for i in c]

Salida:

>>> 
['I am free', 'I am free too']

A medida que foo está devolviendo la bar funciones que está usando su propio valor x , pero no y o z . Por lo tanto, vienen bajo __closure__ .

Beazley pg 100 menciona:

>>>python.__closure__
(<cell at 0x67f50: str object at 0x69230>,)
>>>python.__closure__[0].cell_contents

Mi entendimiento es que __closure__ es una lista, pero ¿qué es todo este objeto de celda y objeto str? ¿Eso parece una tupla de 1 aría?


Las celdas de cierre se refieren a los valores necesarios para la función, pero se toman del ámbito circundante.

Cuando Python compila una función anidada, anota las variables a las que hace referencia, pero solo están definidas en una función primaria (no global) en los objetos de código tanto para la función anidada como para el ámbito principal. Estos son los co_freevars y co_cellvars en los objetos __code__ de estas funciones, respectivamente.

Luego, cuando realmente crea la función anidada (lo que sucede cuando se ejecuta la función principal), esas referencias se utilizan para adjuntar un cierre a la función anidada.

El cierre de una función contiene una tupla de celdas, una para cada variable libre (nombrada en co_freevars ); las celdas son referencias especiales a variables locales de un ámbito principal, que siguen los valores a los que apuntan esas variables locales. Esto se ilustra mejor con un ejemplo:

def foo():
    def bar():
        print(spam)

    spam = 'ham'
    bar()
    spam = 'eggs'
    bar()
    return bar

b = foo()
b()

En el ejemplo anterior, la bar funciones tiene una celda de cierre, que apunta a spam en la función foo . La celda sigue el valor del spam . Más importante aún, una vez que se completa foo() y se devuelve la bar , la celda continúa haciendo referencia al valor (la cadena de eggs ) aunque ya no existe la variable spam dentro de foo .

Por lo tanto, el código anterior genera:

>>> b=foo()
ham
eggs
>>> b()
eggs

y b.__closure__[0].cell_contents es 'eggs' .

Tenga en cuenta que el cierre se anula cuando se llama a la bar() ; El cierre no captura el valor aquí. Eso hace una diferencia cuando produce funciones anidadas (con expresiones lambda o declaraciones def ) que hacen referencia a la variable de bucle:

def foo():
    bar = []
    for spam in ('ham', 'eggs', 'salad'):
        bar.append(lambda: spam)
    return bar

for bar in foo():
    print bar()

Lo anterior imprimirá la salad tres veces seguidas, porque las tres funciones lambda referencia a la variable de spam , no al valor al que estaba vinculado cuando se creó el objeto de función. En el momento for finaliza el bucle for , el spam estaba vinculado a la 'salad' , por lo que los tres cierres se resolverán con ese valor.


>>> def f():
...     a = "HELO"
...     b = 1.0
...     def w(c):
...         return a,b,c
...     return w

>>> w = f()
>>> w.__closure__
(<cell at 0xa05c4ac: str object at 0x9e91b74>, <cell at 0xa05c3bc: float object at 0xb733dde8>)
>>> w.__closure__[0].cell_contents
'HELO'
>>> w.__closure__[1].cell_contents
1.0

Nunca he visto el tipo de celular usado en ningún otro lugar. Parece ser construido específicamente para contener variables de cierre.







python-internals