2009-03-03 11 views
8

W Perl 5.10, mogę powiedzieć:Czy w Pythonie występują zmienne "stan" Perla 5.10?

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

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

... i będzie wydrukować:

1 
2 
3 

Czy Python mieć coś takiego?

+1

Aby pytonować fanów: Należy zauważyć, że zmienne stanu nie są używane tylko dla generatorów w Perlu. Są wygodnym sposobem na enkapsulowanie informacji, które muszą przetrwać z pewną funkcją przez całe życie. :) –

Odpowiedz

12

Najbliższa równoległość prawdopodobnie polega na dołączeniu wartości do samej funkcji.

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

foo.bar = 0 

foo() 
foo() 
foo() 

print foo.bar # prints 3 
+0

+1 idiom dla zmiennych statycznych w Pythonie, chociaż w praktyce nigdy ich nie potrzebujesz. – bobince

+0

możesz zwrócić foo.bar – hasen

+1

Czy nie stworzyłeś zmiennej nieprywatnej !? O mój! – tchrist

2

Tak, choć trzeba zadeklarować zmienną globalną najpierw, zanim zostanie napotkany w foo:

x = 0 

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

foo() 
foo() 
foo() 

EDIT: W odpowiedzi na komentarz, to prawda, że ​​pyton nie ma zmiennych statycznych scoped wewnątrz funkcji. Zauważ, że x w tym przykładzie jest wyświetlany jako globalny tylko dla reszty modułu. Załóżmy na przykład, że powyższy kod znajduje się pod numerem test.py. Załóżmy teraz piszesz następujący moduł:

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

wyjście będzie tylko 1 i 2 nie 101 i 102.

+1

Nie to samo, ponieważ zmienna nie ma zasięgu wewnątrz funkcji - jest narażona na resztę kodu. – Arkady

+0

Tak, masz rację. Python nie ma zmiennych statycznych, więc jest to jedyny sposób na zrobienie tego bez przechodzenia przez trasę klasy. Należy jednak zauważyć, że jest to narażone tylko na reszta modułu jako globalna. –

+1

Zmienne stanu są leksykalne, a nie globalne (co jest ich głównym punktem, czymś, co przypomina globalne, które "pamięta", ale bez wad tego, że jest rzeczywistą globalnością). –

17

Klasa może być lepiej pasuje tutaj (i to zazwyczaj lepiej pasuje do niczego z udziałem "stan"):

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

Dlaczego nie: 'self.x + = 1'? – jfs

+0

Po prostu próbuję być jednoznaczny w przykładzie. –

+1

To bardzo ciężkie z tak prostej rzeczy, nie sądzisz? – tchrist

2

Można również użyć czegoś takiego, jak:

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

static = static_num2().next 

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

, aby uniknąć globalnego var. Podniesione z this link o tym samym pytaniu.

+0

złe formatowanie w kodzie – Jiri

+0

Również w dość aktualnym pythonu można wykonać 'static = itertools.count(). Next' i usunąć definicję' static_num2'. – tzot

8

Nie wiem, czy to jest to, czego szukasz, ale Python posiada funkcje generator, który nie zwraca wartości per se, ale obiekt generator, który generuje nową wartość za każdym

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

wykorzystanie:

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

wygląd tutaj, aby uzyskać więcej wyjaśnień na 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

Nie, że jestem polecając to, ale tylko dla zabawy:

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

Działa to ze względu na way mutable default arguments pracy w Pythonie.

5

Oto jeden sposób, aby wdrożyć zamknięcie w Pythonie:

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

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

Pożyczyłem ten przykład verbatim z python mailing list post.

2

Preferowanym sposobem jest użycie class lub generator (yield).

Dla kompletności Oto wariant w/zamknięcie w Pythonie 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

Dla wszystkich Python ≥2,5: import itertools; foo = itertools.count (1) .next – tzot

+0

@ ΤΖΩΤΖΙΟΥ: Wrong. UWAGA: istnieje "print". W każdym razie celem jest pokazanie, jak wiązać nielokalną nazwę. – jfs

0

Oto kolejny brudny tani sposób, aby to zrobić, jest to wariacja na odpowiedź Tryiptich, ale używając dekoratorów

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 
>>> 
"""  
Powiązane problemy