2012-01-11 12 views
6

Ho un metodo all'interno del quale ho bisogno di passare un intero sempre crescente ad un'altra funzione.Un callable autoincrementante?

posso fare questo in questo modo:

def foo(i): 
    print i 

def bar(): 

    class Incrementer(object): 
     def __init__(self, start=0): 
      self.i = start 

     def __get__(self): 
      j = self.i 
      self.i += 1 
      return j 

    number = Incrementer() 
    foo(number) 
    foo(number) 
    foo(number) 

che emette correttamente 0 1 2 ... ma mi sento come se fossi affacciato su un (o built-in) modo molto più semplice di fare questo?

+1

Sei sicuro che il tuo codice funzioni? Il metodo '__get __()' viene chiamato solo quando si recupera un attributo da una classe di nuovo stile, che sembra non succedere qui. –

+0

Sì, funziona bene. Vuoi dire che dovrebbe funzionare solo se lo faccio: 'number = new Incrementer()'? Perché? –

+1

[Dubito che il tuo codice stampi '0 1 2'] (http://ideone.com/kvCE1). E non sto parlando di 'number = new Incrementer()' - sembra che tu stia confondendo le lingue qui, non c'è un operatore 'new' in Python. Sto parlando dell'invocazione di [descrittori] (http://docs.python.org/reference/datamodel.html#descriptors). –

risposta

14

Prova itertools.count() - fa esattamente quello che ti serve:

>>> c = itertools.count() 
>>> next(c) 
0 
>>> next(c) 
1 
>>> next(c) 
2 
+0

Questo è esattamente quello che stavo cercando. Grazie! –

7

In generale, se è necessario mantenere lo stato tra una chiamata a una funzione e l'altra, ciò che si desidera o è un oggetto (la tua soluzione) o un generatore. In alcuni casi uno sarà più semplice dell'altro, ma non c'è nulla di errato con in linea di principio (anche se sembra che tu abbia qualche problema con l'implementazione).

Il suggerimento di Sven, itertools.count(), è un generatore. La sua attuazione è qualcosa di simile:

def count(): 
    i = 0 
    while True: 
     yield i 
     i += 1 

Ora, se si voleva che fosse richiamabile come una funzione, piuttosto che avere a che fare next(c), è possibile definire un wrapper che ha reso così:

def count(c=itertools.count()): 
    return next(c) 

O quella linea inevitabile lambda:

count = lambda c=itertools.count(): next(c) 

Poi count() restituisce il successivo numero intero ogni volta che si chiami.

Naturalmente, se si vuole essere in grado di creare un numero illimitato di funzioni richiamabili, ciascuno con il proprio contatore, è possibile scrivere una fabbrica per questo:

def counter(): 
    return lambda c=itertools.count(): next(c) 

allora è:

c = counter() 
print c() # 0 
print c() # 1 
# etc 

Questo mi sembra ancora più semplice di un oggetto, ma non di molto. Se il tuo stato o la logica fossero più complessi, l'incapsulamento dell'oggetto potrebbe vincere.

+1

In alternativa 'count = itertools.count() .__ next__', o' count = itertools.count(). Next' per Python 2.6 e versioni successive. –

+1

@ F.J: la seconda variante si applica a tutte le versioni 2.x compresa 2.7. '__next __()' è disponibile solo in 3.x. –

Problemi correlati