while tipos listas globales funciones for declarar como python closures scope python-2.x

tipos - Cierre de Python: escribir en la variable en el alcance principal



variables globales python (6)

¿Qué pasa con el uso de una instancia de clase para contener el estado? Instancias una clase y pasa los métodos de instancia a los subs y esas funciones tendrían una referencia a uno mismo ...

Tengo el siguiente código dentro de una función:

stored_blocks = {} def replace_blocks(m): block = m.group(0) block_hash = sha1(block) stored_blocks[block_hash] = block return ''{{{%s}}}'' % block_hash num_converted = 0 def convert_variables(m): name = m.group(1) num_converted += 1 return ''<%%= %s %%>'' % name fixed = MATCH_DECLARE_NEW.sub('''', template) fixed = MATCH_PYTHON_BLOCK.sub(replace_blocks, fixed) fixed = MATCH_FORMAT.sub(convert_variables, fixed)

Agregar elementos a stored_blocks funciona bien, pero no puedo aumentar num_converted en la segunda subfunción:

UnboundLocalError: variable local ''num_converted'' a la que se hace referencia antes de la asignación

Podría usar variables global pero las globales son feas y realmente no necesito que esa variable sea global en absoluto.

Entonces, tengo curiosidad de cómo puedo escribir en una variable en el alcance de la función principal. nonlocal num_converted probablemente haga el trabajo, pero necesito una solución que funcione con Python 2.x.


(ver a continuación la respuesta editada)

Puedes usar algo como:

def convert_variables(m): name = m.group(1) convert_variables.num_converted += 1 return ''<%%= %s %%>'' % name convert_variables.num_converted = 0

De esta forma, num_converted funciona como una variable "estática" similar a C del método convert_variable

(editado)

def convert_variables(m): name = m.group(1) convert_variables.num_converted = convert_variables.__dict__.get("num_converted", 0) + 1 return ''<%%= %s %%>'' % name

De esta forma, no necesita inicializar el contador en el procedimiento principal.


Modificado de: https://.com/a/40690954/819544

Puede aprovechar el módulo de inspect para acceder al dict global de scope scope y escribir en eso. Eso significa que este truco incluso se puede aprovechar para acceder al alcance de la llamada desde una función anidada definida en un submódulo importado.

import inspect def get_globals(scope_level=0): return dict(inspect.getmembers(inspect.stack()[scope_level][0]))["f_globals"] num_converted = 0 def foobar(): get_globals(0)[''num_converted''] += 1 foobar() print(num_converted) # 1

Juega con el argumento scope_level según sea necesario. Setting scope_level=1 funciona para una función definida en un submódulo, scope_level=2 para la función interna definida en un decorador en un submódulo, etc.

NB: Solo porque puedas hacer esto, no significa que debas hacerlo.


Tengo un par de comentarios.

En primer lugar, aparece una aplicación para tales funciones anidadas cuando se trata de devoluciones de llamada sin formato, como se usan en bibliotecas como xml.parsers.expat. (Que los autores de la biblioteca eligieron este enfoque puede ser objetable, pero ... hay razones para usarlo de todos modos).

Segundo: dentro de una clase, hay alternativas mucho mejores a la matriz (num_converted [0]). Supongo que esto es de lo que Sebastjan estaba hablando.

class MainClass: _num_converted = 0 def outer_method( self ): def convert_variables(m): name = m.group(1) self._num_converted += 1 return ''<%%= %s %%>'' % name

Todavía es lo suficientemente extraño como para merecer un comentario en el código ... Pero la variable es al menos local para la clase.


Usar la palabra clave global está bien. Si tú escribes:

num_converted = 0 def convert_variables(m): global num_converted name = m.group(1) num_converted += 1 return ''<%%= %s %%>'' % name

... num_converted no se convierte en una "variable global" (es decir, no se vuelve visible en ningún otro lugar inesperado), solo significa que se puede modificar dentro de convert_variables . Eso parece ser exactamente lo que quieres.

Para decirlo de otra manera, num_converted ya es una variable global. Todo lo que hace la sintaxis global num_converted es decirle a Python "dentro de esta función, no crear una variable num_converted local, en su lugar, usar la global existente".


Problema: Esto se debe a que las reglas de alcance de Python están dementes. La presencia del operador de asignación += marca el objetivo, num_converted , como local para el alcance de la función num_converted , y no hay forma de sonido en Python 2.x para acceder a un solo nivel de alcance desde allí. Solo la palabra clave global puede sacar las referencias de variables del alcance actual y lo lleva directamente a la parte superior.

Solución: convierte num_converted en una matriz de un solo elemento.

num_converted = [0] def convert_variables(m): name = m.group(1) num_converted[0] += 1 return ''<%%= %s %%>'' % name