¿Variable estática en Python?

En C ++ tenemos una palabra clave estática que en los bucles es algo como esto:

for(int x=0; x<10; x++) { for(int y=0; y<10; y++) { static int number_of_times = 0; number_of_times++; } } 

La estática aquí hace que number_of_times inicialicen una vez. ¿Cómo puedo hacer lo mismo en Python 3.x?

EDITAR: Dado que la mayoría de las personas se confundieron, me gustaría señalar que el código que di es solo un ejemplo de uso estático en C ++. Mi problema real es que quiero inicializar solo UNA variable de tiempo en la función ya que no quiero que sea un parámetro global (¡bla!) O predeterminado …

Suponiendo que lo que quiere es “una variable que se inicializa solo una vez en la primera llamada de función”, no hay tal cosa en la syntax de Python. Pero hay maneras de obtener un resultado similar:

1 – Utilizar un global. Tenga en cuenta que en Python, ‘global’ realmente significa ‘global al módulo’, no ‘global al proceso’:

 _number_of_times = 0 def yourfunc(x, y): global _number_of_times for i in range(x): for j in range(y): _number_of_times += 1 

2 – Envuelva el código en una clase y use un atributo de clase (es decir, un atributo compartido por todas las instancias). :

 class Foo(object): _number_of_times = 0 @classmethod def yourfunc(cls, x, y): for i in range(x): for j in range(y): cls._number_of_times += 1 

Tenga en cuenta que utilicé un classmethod ya que este fragmento de código no necesita nada de una instancia

3 – Envuelva su código en una clase, use un atributo de instancia y proporcione un acceso directo para el método:

 class Foo(object): def __init__(self): self._number_of_times = 0 def yourfunc(self, x, y): for i in range(x): for j in range(y): self._number_of_times += 1 yourfunc = Foo().yourfunc 

4 – Escribe una clase que se pueda llamar y proporciona un atajo:

 class Foo(object): def __init__(self): self._number_of_times = 0 def __call__(self, x, y): for i in range(x): for j in range(y): self._number_of_times += 1 yourfunc = Foo() 

4 bis – usa un atributo de clase y una metaclase

 class Callable(type): def __call__(self, *args, **kw): return self._call(*args, **kw) class yourfunc(object): __metaclass__ = Callable _numer_of_times = 0 @classmethod def _call(cls, x, y): for i in range(x): for j in range(y): cls._number_of_time += 1 

5 – Haga un uso “creativo” de los argumentos predeterminados de la función que se creará una sola vez en la importación del módulo:

 def yourfunc(x, y, _hack=[0]): for i in range(x): for j in range(y): _hack[0] += 1 

Todavía hay otras posibles soluciones / hacks, pero creo que ahora se tiene una idea general.

EDITAR: dadas las aclaraciones de la operación, es decir, “Digamos que tiene una función recursiva con el parámetro predeterminado, pero si alguien intenta dar un argumento más a su función, podría ser catastrófico”, parece que lo que realmente quiere la OP es algo como:

 # private recursive function using a default param the caller shouldn't set def _walk(tree, callback, level=0): callback(tree, level) for child in tree.children: _walk(child, callback, level+1): # public wrapper without the default param def walk(tree, callback): _walk(tree, callback) 

Lo que, por cierto, demuestra que realmente tuvimos otro problema XY …

Python no tiene variables estáticas por diseño . Para su ejemplo, y para usar dentro de bloques de bucle, etc. en general, solo usa una variable en un ámbito externo; si eso hace que sea demasiado longeva, podría ser el momento de considerar dividir esa función en otras más pequeñas.

Para una variable que sigue existiendo entre las llamadas a una función, eso es simplemente reimplementar la idea básica de un objeto y un método en ese objeto, por lo que debería hacer una de esas en su lugar.

Puede crear un cierre con nonlocal para hacerlos editables (solo en python 3.x). Aquí hay un ejemplo de una función recursiva para calcular la longitud de una lista.

 def recursive_len(l): res = 0 def inner(l2): nonlocal res if l2: res += 1 inner(l2[1:]) inner(l) return res 

O bien, puede asignar un atributo a la función en sí. Usando el truco desde aquí :

 def fn(self): self.number_of_times += 1 fn.func_defaults = (fn,) fn.number_of_times = 0 fn() fn() fn() print (fn.number_of_times) 

También puede utilizar la palabra clave global:

 def main(args): for i in xrange(10): print i global tmp tmp = i 

Pero tenga cuidado … La mayoría de los casos agregará más problemas de los que resuelve.

La otra forma basada en la función de hacer esto en Python es:

 def f(arg, static_var=[0]): static_var[0] += arg 

A medida que el objeto static_var se inicializa en la definición de la función y luego se reutiliza para todas las llamadas, actuará como una variable estática. Tenga en cuenta que no puede usar un int , ya que son inmutables.

 >>> def f(arg, static_var=[0]): ... static_var[0] += arg ... print(static_var[0]) ... >>> f(1) 1 >>> f(2) 3 >>> f(3) 6