2012-04-06 32 views
6

considerare la funzione ipotetico repeatcall, che prende come argomenti mancato args richiamabile func e un intero positivo n, e restituisce un elenco del quale sono ottenuti eseguendo func()n volte. Supporta un flusso infinito di hijinks stupide come:Funzione per chiamare ripetutamente una funzione?

>>> repeatcall(lambda: id(dict()), 5) 
[45789920, 45788064, 45807216, 45634816, 45798640] 

>>> urandom = lambda: struct.unpack('Q', open('/dev/urandom').read(8))[0] 
>>> repeatcall(urandom, 3) 
[3199039843823449742, 14990726001693341311L, 11583468019313082272L] 

>>> class Counter(itertools.count): __call__ = itertools.count.next 
>>> repeatcall(Counter(100, -2), 4) 
[100, 98, 96, 94] 

Potrei giurare che ho visto una funzione come repeatcall da qualche parte nelle librerie standard di Python 2.x, ma non riesco a trovarlo. Se non ho sognato questo, dove nella libreria standard posso trovarlo?

PS: So che è banale rotolare il proprio, ma odio reinventare le ruote, specialmente quelle che sono già nella libreria standard. Sono non chiedendo come fare il mio.

Edit: ha reso ancora più esplicito che io non sto chiedendo come codice repeatcall.

+1

non è solo mappatura su un intervallo? – gbulmer

risposta

13

Hai visto questo nella documentazione della libreria standard, non la libreria standard stesso.

E 'repeatfunc dalla itertools recipes:

def repeatfunc(func, times=None, *args): 
    """Repeat calls to func with specified arguments. 

    Example: repeatfunc(random.random) 
    """ 
    if times is None: 
     return starmap(func, repeat(args)) 
    return starmap(func, repeat(args, times)) 

Permette argomenti e dovrebbe (in teoria) di eseguire meglio di una lista di comprensione perché func deve solo essere guardato una volta. repeat è anche più veloce di range per quando non si sta effettivamente utilizzando il contatore.

+1

Tecnicamente anche la tua non è la risposta esatta, a meno che tu non stia dicendo che non esiste nello stdlib. Non penso che una ricetta che usa 'itertools.starmap' sia diversa dalla tua. Anche se suppongo che dimostrando questo, sei in un giro di strada dicendo che devi tirare il tuo. – jdi

+1

@jdi Sì, sto restando che non esiste nella libreria standard. Si ricorda di averlo visto perché è nei documenti. Questa è la risposta alla sua domanda. – agf

+1

Quindi suppongo che il 90% di quello che hai scritto non sia necessario se non è interessato a vedere eventuali implementazioni del codice. Quindi, davvero, quel 90% è uguale agli altri. – jdi

3

Vuoi dire qualcosa di simile ?:

>> from random import random 
>> print [random() for x in range(5)] 
[0.015015074309405185, 
0.7877023608913573, 
0.2940706206824023, 
0.7140457069245207, 
0.07868376815555878] 

sembra abbastanza succinta no?

+2

"So che è banale rotolare il proprio, ma odio reinventare le ruote" - questo non risponde alla domanda. – agf

2

è possibile utilizzare la funzione built-in apply per questo scopo

>>> def repeatcall(func,n): 
    [apply(func) for i in range(0,n)] 

>>> repeatcall(lambda: id(dict()), 5) 
[56422096, 56422240, 56447024, 56447168, 56447312] 

>>> import itertools 
>>> class Counter(itertools.count): __call__ = itertools.count.next 

>>> repeatcall(Counter(100, -2), 4) 
[100, 98, 96, 94] 
>>> 

Nota ** Dal manuale L'uso di apply() è equivalente alla funzione (* args, ** parole chiave).

Così repeatcall può anche essere scritta come

>>> def repeatcall(func,n): 
    [func() for i in range(0,n)] 
+1

'apply' è stato deprecato da python2.3. Puoi semplicemente chiamare la funzione con i suoi * args e ** kwargs – jdi

+0

la funzione può essere chiamata direttamente, anche se il suo nome è passato come argomento: def repeatcall (func, n): return [func() per i in range (0, n)] –

+0

sì applicare è completamente inutile qui e altrove. –

3

C'è un motivo per cui questo non esiste: il modo idiomatico di codificare una funzione che non accetta argomenti per ogni chiamata e restituisce qualcosa di nuovo è codificarlo come generatore.

Si utilizzerà quindi un'espressione di lista o di generatore per chiamarla tutte le volte che si desidera: [next(gen) for i in xrange(5)]. Meglio ancora, gen può essere il risultato di un'espressione di generatore come (id(dict()) for i in (itertools.repeat(None))).

Quindi, python non supporta la libreria perché supporta sintatticamente.

+0

Hai ragione, è più "Pythonico" della soluzione nelle ricette "itertools". Ma, come tutti gli altri, questa non è una risposta alla domanda. Stava chiedendo dove aveva visto un'implementazione, non come farlo. Questo sarebbe stato un buon commento. – agf

+1

@agf Non proprio. Ciò richiede almeno due paragrafi e spiega perché non esiste una soluzione del modulo richiesto da OP. – Marcin

+0

La sua domanda non è "questo è nella libreria standard", è "l'ho già visto prima, penso che fosse nella libreria standard ma non riesco a trovarlo." Dove si trova? " Un commento si adatta a 500 caratteri; il tuo post ha spazio libero e nessun blocco formattato che non potresti visualizzare in un commento. – agf