¿Cuál es el equivalente en Python de las variables estáticas dentro de una función?

Resuelto andrewdotnich asked hace 16 años • 32 respuestas

¿Cuál es el equivalente idiomático en Python de este código C/C++?

void foo()
{
    static int counter = 0;
    counter++;
    printf("counter is %d\n", counter);
}

específicamente, ¿cómo se implementa el miembro estático en el nivel de función, a diferencia del nivel de clase? ¿Y colocar la función en una clase cambia algo?

andrewdotnich avatar Nov 11 '08 06:11 andrewdotnich
Aceptado

Un poco al revés, pero esto debería funcionar:

def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter
foo.counter = 0

Si desea que el código de inicialización del contador esté en la parte superior en lugar de en la parte inferior, puede crear un decorador:

def static_vars(**kwargs):
    def decorate(func):
        for k in kwargs:
            setattr(func, k, kwargs[k])
        return func
    return decorate

Luego usa el código como este:

@static_vars(counter=0)
def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter

Desafortunadamente , aún será necesario que uses el foo.prefijo.

(Crédito: @ony )

Claudiu avatar Nov 10 '2008 23:11 Claudiu

Puede agregar atributos a una función y usarla como una variable estática.

def myfunc():
  myfunc.counter += 1
  print myfunc.counter

# attribute must be initialized
myfunc.counter = 0

Alternativamente, si no desea configurar la variable fuera de la función, puede usar hasattr()para evitar una AttributeErrorexcepción:

def myfunc():
  if not hasattr(myfunc, "counter"):
     myfunc.counter = 0  # it doesn't exist yet, so initialize it
  myfunc.counter += 1

De todos modos, las variables estáticas son bastante raras y deberías encontrar un lugar mejor para esta variable, probablemente dentro de una clase.

vincent avatar Nov 10 '2008 23:11 vincent

También se podría considerar:

def foo():
    try:
        foo.counter += 1
    except AttributeError:
        foo.counter = 1

Razonamiento:

  • mucho pitónico ("pedir perdón, no permiso")
  • use una excepción (lanzada solo una vez) en lugar de ifuna rama (piense en la excepción StopIteration )
rav avatar Apr 25 '2013 12:04 rav

Mucha gente ya ha sugerido probar 'hasattr', pero hay una respuesta más sencilla:

def func():
    func.counter = getattr(func, 'counter', 0) + 1

Sin intentar/excepto, sin probar hasattr, solo getattr con un valor predeterminado.

Jonathan avatar Jan 05 '2015 16:01 Jonathan