2009-02-26 33 views
44

Hay un questions asking how to simulate static variables in python.¿Por qué Python no tiene variables estáticas?

Además, en la web se pueden encontrar muchas soluciones diferentes para crear variables estáticas. (Aunque todavía no he visto ninguno que me guste)

¿Por qué Python no admite variables estáticas en los métodos? ¿Esto se considera antiponético o tiene algo que ver con la sintaxis de Python?

Editar:

me preguntó específicamente acerca de la razón por la de la decisión de diseño y no he proporcionado ningún ejemplo de código porque quería evitar la explicación para simular las variables estáticas.

+0

Lo que estaba mal con las respuestas a http://stackoverflow.com/questions/460586/simulating-a-local-static-variable-in -¿pitón? ¿Por qué volver a hacer la pregunta? –

+5

explícitamente no pregunté cómo simularlo, pero cuál es el motivo de esta decisión. –

Respuesta

74

La idea detrás de esta omisión es que las variables estáticas solo son útiles en dos situaciones: cuando realmente deberías estar usando una clase y cuando realmente deberías estar usando un generador.

Si desea adjuntar información de estado a una función, lo que necesita es una clase. Una clase trivialmente simple, tal vez, pero una clase, sin embargo:

def foo(bar): 
    static my_bar # doesn't work 

    if not my_bar: 
     my_bar = bar 

    do_stuff(my_bar) 

foo(bar) 
foo() 

# -- becomes -> 

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

    def __call__(self): 
     do_stuff(self.bar) 

foo = Foo(bar) 
foo() 
foo() 

Si desea el comportamiento de su función para cambiar cada vez que se llama, lo que necesita es un generador:

def foo(bar): 
    static my_bar # doesn't work 

    if not my_bar: 
     my_bar = bar 

    my_bar = my_bar * 3 % 5 

    return my_bar 

foo(bar) 
foo() 

# -- becomes -> 

def foogen(bar): 
    my_bar = bar 

    while True: 
     my_bar = my_bar * 3 % 5 
     yield my_bar 

foo = foogen(bar) 
foo.next() 
foo.next() 

Por supuesto, estático las variables son útiles para secuencias de comandos rápidas y sucias en las que no se desea lidiar con la molestia de grandes estructuras para pequeñas tareas. Pero allí, que realmente no necesita nada más que global - puede parecer un pero kludgy, pero eso está bien para las pequeñas, de una sola vez guiones:

def foo(): 
    global bar 
    do_stuff(bar) 

foo() 
foo() 
+0

Bien por el hecho de que de hecho podrías necesitar una clase. Aparte del feo patrón Borg, no hay una forma real de garantizar que esta clase sea singleton. En realidad, la importación de paquetes hace que sea un dolor. – fulmicoton

+0

La muestra de clase no parece ser Python. Creo que quisiste decir: "private bar" => "bar = None", y en init tendrías "self.my_bar = bar". –

+0

@Heikki Toivonen: De acuerdo, también en el primer ejemplo "my_bar" no tiene que ser una variable de clase, una variable de instancia funcionaría igual de bien. –

6

Creo que la mayoría de los usos de variables estáticas locales es simular generadores, es decir, tener alguna función que realiza alguna iteración de un proceso, devuelve el resultado, pero mantiene el estado para la invocación posterior. Python maneja esto muy elegantemente usando el comando yield, por lo que parece que no hay tanta necesidad de variables estáticas.

+0

Me gustaría usarlos para almacenar cosas cargadas desde el disco. Creo que desordena la instancia menos, si pudiera asignarlos a la función. –

5

Es una opción de diseño.

Asumo Guido piensa que no es necesario muy a menudo, y nunca realmente los necesita: siempre se puede simplemente usar una variable global y decirle a todos que mantengan sus patas grasienta offa' la variable; -)

+0

uh, o podría pasar objetos de forma normal. –

+1

supongamos que quiere usar su propio generador aleatorio en quicksort. ¿Deberían pasar las personas que llaman en la aleatoriedad? No. ¿Debería actualizarse entre llamadas (de otro modo independientes)? Sí. A veces no quieres pasar objetos ... –

+0

Sí, supongo que es un ejemplo correcto, aunque bastante marginal, –

0

La respuesta es más o menos lo mismo que por qué nadie usa estática métodos (aunque existen). Usted tiene un espacio de nombres a nivel de módulo que tiene el mismo propósito que una clase de todos modos.

4

Para el almacenamiento en caché o memoization propósitos, los decoradores se pueden utilizar como una solución elegante y general.

19

Una alternativa a una clase es un atributo de función:

def foo(arg): 
    if not hasattr(foo, 'cache'): 
     foo.cache = get_data_dict() 
    return foo.cache[arg] 

Mientras que una clase es probablemente más limpio, esta técnica puede ser útil y es más agradable, en mi opinión, a continuación, un mundial.

+0

Esto debería ser considerado la solución oficial. +1 – Triptych

+1

Lo que no me gusta es la necesidad de escribir el nombre del método una y otra vez. Si cambiara el nombre, tendría que volver a escribir la mitad del código. –

+1

@gs: Sí, esto es una deficiencia. Estaba buscando alguna forma de referenciar la función actual en lugar de usar el nombre (algo así como self) pero no creo que exista tal forma.Podrías hacer un "this = foo" en la parte superior y luego hacer referencia a "this" en todas partes para que el cambio de nombre sea fácil de mantener. – davidavr

0

Una alternativa desacertada:

También puede utilizar los efectos secundarios de la evaluación del tiempo definición de los valores predeterminados de la función:

def func(initial=0, my_static=[]) 
    if not my_static: 
    my_static.append(initial) 

    my_static[0] += 1 
    return my_static[0] 

print func(0), func(0), func(0) 

Su realmente fea y fácilmente subvertido, pero funciona. Usar global sería más limpio que esto, imo.

-1

De uno de sus comentarios: "Me gustaría usarlos para almacenar en caché cosas cargados desde el disco creo que estorba la instancia inferior, si pudiera asignarlos a la función"

utilizar una clase de almacenamiento en caché luego, como una clase o atributo de instancia para su otra clase. De esta forma, puede usar el conjunto completo de características sin saturar otras cosas. Además, obtienes una herramienta reutilizable.

Esto muestra que en SO siempre vale la pena declarar el problema en lugar de pedir una solución específica de bajo nivel (por ejemplo, para una característica de idioma faltante). De esa manera, en lugar de interminables debates sobre la simulación de "estática" (una característica obsoleta de un idioma antiguo, en mi opinión) alguien podría haberle dado una buena respuesta a su problema antes.

+0

Sabía cómo simularlos. La pregunta fue específicamente sobre la decisión. –

8

En Python 3, me gustaría utilizar un cierre:

def makefoo(): 
    x = 0 
    def foo(): 
     nonlocal x 
     x += 1 
     return x 
    return foo 

foo = makefoo() 

print(foo()) 
print(foo()) 
+0

hola todavía estoy tratando de descubrir cómo funciona esto. ¿Puedes explicar un poco más? Gracias por adelantado. :) – BugShotGG

Cuestiones relacionadas