2009-02-26 12 views
44

C'è un questions asking how to simulate static variables in python.Perché Python non ha variabili statiche?

Inoltre, sul Web si possono trovare molte soluzioni diverse per creare variabili statiche. (Anche se non ne ho visto uno che mi piace ancora.)

Perché Python non supporta variabili statiche nei metodi? È considerato unpitonico o ha qualcosa a che fare con la sintassi di Python?

Edit:

ho chiesto specificamente del perché della decisione di progettazione e non ho fornito alcun esempio di codice perché volevo evitare di spiegazione per simulare variabili statiche.

+0

cosa non andava con le risposte alle http://stackoverflow.com/questions/460586/simulating-a-local-static-variable-in -pitone? Perché ri-chiedere la domanda? –

+5

Non ho chiesto esplicitamente come simularlo, ma quale sia la ragione di questa decisione. –

risposta

74

L'idea alla base di questa omissione è che le variabili statiche sono utili solo in due situazioni: quando si dovrebbe realmente usare una classe e quando si dovrebbe usare un generatore.

Se si desidera allegare informazioni di stato a una funzione, ciò di cui si ha bisogno è una classe. Una classe banalmente semplice, forse, ma una classe comunque:

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() 

Se si desidera il comportamento del vostro funzione per cambiare ogni volta che si chiama, quello che ti serve è un generatore:

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() 

Naturalmente, statica le variabili sono utili per script veloci e sporchi in cui non si desidera gestire la seccatura di grandi strutture per piccole attività. Ma c'è, non si ha realmente bisogno di qualcosa di più di global - se può sembrare un ma kludgy, ma va bene per i piccoli, una tantum script:

def foo(): 
    global bar 
    do_stuff(bar) 

foo() 
foo() 
+0

Ok per il fatto che in effetti potresti aver bisogno di una lezione. A parte il brutto modello di Borg, non esiste un modo reale per garantire che questa classe sia un singleton. In realtà l'importazione del pacchetto lo rende piuttosto un dolore. – fulmicoton

+0

L'esempio di classe non sembra che sia Python. Penso che intendessi: "private bar" => "bar = None", e in init avresti "self.my_bar = bar". –

+0

@Heikki Toivonen: concordato, anche nel primo esempio "my_bar" non deve essere una variabile di classe, una variabile di istanza potrebbe funzionare altrettanto bene. –

6

Penso che la maggior parte degli usi delle variabili statiche locali sia di simulare i generatori, cioè di avere una funzione che esegue l'iterazione di un processo, restituisce il risultato, ma mantiene lo stato per la successiva chiamata. Python lo gestisce in modo molto elegante usando il comando yield, quindi sembra che non ci sia così tanto bisogno di variabili statiche.

+0

Mi piacerebbe usarli per memorizzare le cose caricate dal disco. Penso che ingombra l'istanza di meno, se potessi assegnarli alla funzione. –

5

È una scelta di design.

Sto assumendo Guido pensa che tu non hai bisogno di loro molto spesso, e non avete mai realmente bisogno di loro: si può sempre e solo utilizzare una variabile globale e dire a tutti di mantenere la loro zampe grassa offa' la variabile; -)

+0

o potresti passare gli oggetti normalmente. –

+1

supponiamo che tu voglia usare il tuo generatore casuale in quicksort. I chiamanti dovrebbero passare nella casualità? No. Dovrebbe essere aggiornato tra chiamate (altrimenti indipendenti)? Sì. A volte non vuoi passare intorno agli oggetti ... –

+0

Sì, immagino che sia un esempio corretto, anche se marginale, –

0

La risposta è più o meno lo stesso motivo per cui nessuno usa statica metodi (anche se esistono). Hai uno spazio dei nomi a livello di modulo che serve allo stesso scopo di una classe.

4

Per gli scopi di memorizzazione nella cache o memoization, i decoratori possono essere utilizzati come soluzione elegante e generale.

19

Un'alternativa a una classe è un attributo funzione:

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

Mentre una classe è probabilmente più pulito, questa tecnica può essere utile e più bello è, a mio parere, quindi a livello globale.

+0

Questo dovrebbe essere considerato la soluzione ufficiale. +1 – Triptych

+1

Quello che non mi piace è la necessità di scrivere il nome del metodo più e più volte. Se avessi cambiato il nome dovrei riscrivere metà del codice. –

+1

@gs: Sì, questa è una mancanza. Stavo cercando un modo per fare riferimento alla funzione corrente invece di usare il nome (qualcosa di simile a me stesso), ma non credo che ci sia un tale modo.Si potrebbe fare un "this = foo" in alto e quindi fare riferimento a "questo" ovunque, in modo che una rinomina sia facile da mantenere. – davidavr

0

Un mal consigliato alternativa:

È inoltre possibile utilizzare gli effetti collaterali della valutazione momento definizione di default funzione:

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) 

sua davvero brutto e facilmente sovvertito, ma funziona. Usare global sarebbe più pulito di questo, imo.

-1

da uno dei vostri commenti: "Mi piacerebbe usarli per memorizzare nella cache le cose caricati da disco Penso che ingombra l'istanza di meno, se potessi assegnare alla funzione"

utilizzare una classe di caching quindi, come un attributo di classe o istanza per l'altra classe. In questo modo, puoi utilizzare l'intero set di classi di funzioni senza ingombrare altre cose. Inoltre, si ottiene uno strumento riutilizzabile.

Questo mostra che su SO si paga sempre per enunciare il proprio problema invece di chiedere una soluzione specifica di basso livello (ad esempio per una caratteristica della lingua mancante). In questo modo, invece di infiniti dibattiti sulla simulazione di "statico" (una caratteristica deprecata da un linguaggio antico, secondo me) qualcuno avrebbe potuto dare una buona risposta al problema prima.

+0

Sapevo come simularli. La domanda riguardava specificamente la decisione. –

8

In Python 3, vorrei usare una chiusura:

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

foo = makefoo() 

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

ciao sto ancora cercando di capire come funziona. Puoi spiegarci un po 'di più? Grazie in anticipo. :) – BugShotGG

Problemi correlati