2009-03-03 12 views
8

En Perl 5.10, lo que puedo decir:¿Tiene Python algo así como las variables de "estado" de Perl 5.10?

sub foo() { 
    state $x = 1; 
    say $x++; 
} 

foo(); 
foo(); 
foo(); 

... y que va a imprimir:

1 
2 
3 

¿El Python tiene algo como esto?

+1

Para los fanáticos de pitón: Tenga en cuenta que las variables de estado no solo se utilizan para generadores en Perl. Son una forma práctica de encapsular información que necesita persistir con alguna función a lo largo de su vida útil. :) –

Respuesta

12

El paralelo más cercano es probablemente para adjuntar valores a la función en sí.

def foo(): 
    foo.bar = foo.bar + 1 

foo.bar = 0 

foo() 
foo() 
foo() 

print foo.bar # prints 3 
+0

idioma +1 para variables estáticas en Python, aunque en la práctica nunca los necesita. – bobince

+0

puede devolver foo.bar – hasen

+1

¿No acaba de crear una variable no privada? ¡Oh mi! – tchrist

2

Sí, aunque usted tiene que declarar su variable global en primer lugar antes de que se encuentra en foo:

x = 0 

def foo(): 
    global x 
    x += 1 
    print x 

foo() 
foo() 
foo() 

EDIT: En respuesta a la observación, es cierto que Python no tiene variables estáticas con ámbito dentro de una función. Tenga en cuenta que x en este ejemplo solo está expuesto como global al resto del módulo. Por ejemplo, supongamos que el código anterior está en test.py. Ahora supongamos que escribir el siguiente módulo:

from test import foo 
x = 100 
foo() 
foo() 

La salida sólo será 1 y 2, no 101 y 102.

+1

No es lo mismo, porque la variable no tiene un alcance dentro de la función: está expuesta al resto del código. – Arkady

+0

Sí, tienes razón. Python no tiene variables estáticas, por lo que esta es la única forma de hacerlo sin ir a la ruta de clase. Sin embargo, tenga en cuenta que esto solo está expuesto al resto del módulo como global. –

+1

las variables de estado son léxicas, no globales (que es el punto principal de ellas, algo COMO un global que 'recuerda' pero sin los inconvenientes de ser un global real) –

17

Una clase puede ser una mejor opción aquí (y es por lo general un mejor ajuste para cualquier cosa que implica "Estado"):

class Stateful(object): 

    def __init__(self): 
     self.state_var = 0 

    def __call__(self): 
     self.state_var = self.state_var + 1 
     print self.state_var 

foo = Stateful() 
foo() 
foo() 
+0

¿Por qué no: 'self.x + = 1'? – jfs

+0

Solo trato de ser explícito en el ejemplo. –

+1

Eso es bastante pesado para algo tan simple, ¿no crees? – tchrist

2

También podría usar algo como

def static_num2(): 
    k = 0 
    while True: 
     k += 1 
     yield k 

static = static_num2().next 

for i in range(0,10) : 
    print static() 

para evitar una var. Global Levantado de this link sobre la misma pregunta.

+0

mal formato en su código – Jiri

+0

Además, en una python bastante reciente, puede hacer 'static = itertools.count(). Next' y descartar la definición' static_num2'. – tzot

8

No estoy seguro si esto es lo que está buscando, pero Python tiene funciones del generador que no devuelven un valor per se, sino un objeto generador que genera un nuevo valor de cada

def gen(): 
    x = 10 
    while True: 
     yield x 
     x += 1 

uso:

>>> a = gen() 
>>> a.next() 
10 
>>> a.next() 
11 
>>> a.next() 
12 
>>> a.next() 
13 
>>> 

vistazo aquí para obtener más explicaciones sobre yield:
What does the "yield" keyword do in Python?

1
>>> def foo(): 
    x = 1 
    while True: 
     yield x 
     x += 1 


>>> z = iter(foo()) 
>>> next(z) 
1 
>>> next(z) 
2 
>>> next(z) 
3 
2

No es que yo estoy recomendando esto, pero sólo por diversión:

def foo(var=[1]): 
    print var[0] 
    var[0] += 1 

Esto funciona debido a la way mutable default arguments trabajo en Python.

5

Aquí es una manera de poner en práctica un cierre en Python:

def outer(): 
    a = [4] 
    def inner(): 
     print a[0] 
     a[0] = a[0] + 1 
    return inner 

fn = outer() 
fn() # => 4 
fn() # => 5 
fn() # => 6 

Tomé prestado este ejemplo textualmente de un python mailing list post.

2

La forma preferible es usar class o generator (yield).

En aras de la exhaustividad aquí es una variante w/cierre en Python 3.x:

>>> def make_foo(): 
...  x = 1 
...  def foo(): 
...   nonlocal x 
...   print(x) 
...   x += 1 
...  return foo 
... 
>>> foo = make_foo() 
>>> foo() 
1 
>>> foo() 
2 
>>> foo() 
3 
+0

Para todos Python ≥2.5: importar itertools; foo = itertools.count (1) .next – tzot

+0

@ ΤΖΩΤΖΙΟΥ: Incorrecto. NOTA: hay una 'impresión'. De todos modos, el propósito es demostrar cómo vincular el nombre no local. – jfs

0

es otra forma barata sucia hacerlo aquí, que es una variación de la respuesta de Tryiptich, pero utilizando decoradores

def static_var(name, value): 
    def dec(function): 
     setattr(function, name, value) 
     return function 
    return dec 


@static_var('counter', 0) 
def counting_function(): 
    counting_function.counter = counting_function.counter + 1 
    print counting_function.counter 



""" 
>>> counting_function() 
1 
>>> counting_function() 
2 
>>> counting_function() 
3 
>>> counting_function() 
4 
>>> counting_function() 
5 
>>> 
"""  
Cuestiones relacionadas