2012-06-22 29 views
11

tengo un método que he entrado en funciones anidadas más pequeños para romper la base de código:llamada función anidada en Python

def foo(x,y): 
    def do_this(x,y): 
     pass 
    def do_that(x,y): 
     pass 
    do_this(x,y) 
    do_that(x,y) 
    return 

¿Hay una forma de ejecutar una de las funciones anidadas por sí mismo. por ejemplo:

foo.do_this(x,y) 

EDIT:

Estoy tratando de almacenamiento en caché de configuración en un servidor web que he construido utilizando pyramid_breaker

def getThis(request): 
    def invalidate_data(getData,'long_term',search_term): 
     region_invalidate(getData,'long_term',search_term) 
    @cached_region('long_term') 
    def getData(search_term): 
     return response 
    search_term = request.matchdict['searchterm'] 
    return getData(search_term) 

Este es mi entendimiento puede no ser exacta:

Ahora la razón por la que tengo esto es que el espacio de nombres utilizado por el decorador para crear la clave de caché se genera desde la función y los argumentos. Por lo tanto, no puede simplemente poner el decorador en getThis ya que la variable request es unique-ish y la caché es inútil. Así que creé la función interna que tiene args repetibles (search_term).

Sin embargo, para invalidar la memoria caché (es decir, actualizar), la función de invalidación requiere un alcance para conocer la función 'getData', por lo que también debe estar anidada. Por lo tanto, necesito llamar a la función anidada. Ustedes personas maravillosas han dejado en claro que no es posible así que ¿alguien puede explicar cómo podría hacerlo con una estructura diferente?

+0

su código 'foo.do_this' intentará do_this de acceso como miembro de func ion de 'foo', que le dará un error de atributo, en su lugar hacer foo como una clase – avasal

+0

" romper la base de código "es lo que los espacios de nombres de los módulos son buenos. Si realmente quieres * encapsular * las funciones 'do_', utiliza una clase como muestra @lazyr. – msw

+0

Las funciones anidadas no son la forma de estructurar el código en Python (tampoco lo son las clases). Eche un vistazo a [modules] (http://docs.python.org/tutorial/modules.html). – georg

Respuesta

19

Asumo do_this y do_that son en realidad depende de algún argumento de foo, ya que de lo contrario podría simplemente sacarlos de foo y llamarlos directamente.

Sugiero volver a trabajar todo el asunto como una clase. Algo como esto:

class Foo(object): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

    def do_this(self): 
     pass 

    def do_that(self): 
     pass 

    def __call__(self): 
     self.do_this() 
     self.do_that() 

foo = Foo(x, y) 
foo() 
foo.do_this() 
+0

Respuesta muy útil y parece que toda mi estructura puede estar equivocada. Podría ser más útil si explico la imagen más grande para ver si puede ayudar (no se preocupe si es demasiado difícil). – user1474424

+2

@ user1474424 Creo que deberías poner esto en una nueva pregunta. –

+0

He hecho una edición a la pregunta. ¿Es mejor crear una nueva pregunta, lo siento, una nueva para desbordar la pila? – user1474424

3

No, no lo hay. Dado que es posible acceder a las variables en un ámbito exterior desde el interior de una función anidada:

def foo(x,y): 
    def do_this(z): 
     print(x,y,z) 
    # ... 

no hay manera de llamar do_this la vez que proporciona un enlace para x y y.

Si debe llamar al do_this desde otro lugar, simplemente haga que sea una función de nivel superior en el mismo nivel que foo.

2

No (aparte de hurgar en los objetos de cierre, que es una exageración completa aquí). Si lo necesitas, usa una clase.

class foo(object): 
    def do_this(self, x, y): 
     ... 
    def do_that(self, x, y): 
     ... 
    def do_other_stuff(self, x, y): 
     # or __call__, possibly 

o simplemente poner esas funciones en el ámbito exterior, ya que todo lo que estás pasando como argumentos de todos modos:

def foo(x, y): 
    do_this(x, y) 
    do_that(x, y) 

def do_this(x, y): 
    ... 

def do_that(x, y): 
    ... 
1

No, usted tiene que hacer como un atributo del objeto función. Pero esto solo funcionará después de la primera llamada de foo.

def foo(x,y): 
    def do_this(x,y): 
     pass 
    def do_that(x,y): 
     pass 
    do_this(x,y) 
    do_that(x,y) 
    foo.do_this = do_this 
    foo.do_that = do_that 
    return 

>>> foo.do_this(1, 2) 
AttributeError: 'function' object has no attribute 'do_this' 
>>> foo(1, 2) 
>>> foo.do_this(1, 2) 
>>> 
7

Estas respuestas anteriores, que le dice que no se puede hacer esto, por supuesto, son mal. Esto es python, puedes hacer casi cualquier cosa que desees usando magia de código mágico.

Podemos tomar el primer código de función constante de foo, esta será la función do_this. Entonces podemos usar este código para crear una nueva función con él.

ver https://docs.python.org/2/library/new.html para obtener más información sobre el nuevo y https://docs.python.org/2/library/inspect.html para obtener más información sobre cómo llegar al código interno.

Advertencia: no es porque se puede hacer esto que usted debe hacer esto, reconsiderando la forma en que han estructurado sus funciones es el camino a seguir, pero si quieres un corte rápido y sucio que probablemente se romperá en el futuro, aquí van:

import new 
myfoo = new.function(foo.func_code.co_consts[1],{}) 
myfoo(x,y) # hooray we have a new function that does what I want 

ACTUALIZACIÓN: en python3 puede utilizar el módulo de tipos con foo.__code__:

import types 
myfoo = types.FunctionType(foo.__code__.co_consts[1], {}) 
myfoo() # behaves like it is do_this() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: do_this() missing 2 required positional arguments: 'x' and 'y' 
+0

En Python 3 puedo usar 'types'? –

+0

@VitalyZdanevich Sí, según la [documentación] (https://docs.python.org/2/library/new.html): 'En desuso desde la versión 2.6: el nuevo módulo se ha eliminado en Python 3. Utilice los tipos en su lugar, las clases del módulo. – Pedro

+0

Esta debería ser la respuesta aceptada – noamt

Cuestiones relacionadas