2012-11-30 12 views
12

Was ist ein idiomatic Weg, um einen unendlichen Iterator von einer Funktion zu erstellen? Zum BeispielPython: Iterator von einer Funktion

from itertools import islice 
import random 
rand_characters = to_iterator(random.randint(0,256)) 
print ' '.join(islice(rand_characters, 100)) 

würde produzieren 100 Zufallszahlen

+0

Für die oben würden Sie 'os.urandom (100)' verwenden obwohl würden Sie nicht? –

+0

@ JonClements: natürlich ist es nur ein Beispiel. –

Antwort

17

Sie wollen einen Iterator, die Werte kontinuierlich ergibt, bis Sie es für neue stoppen zu fragen? Verwenden Sie einfach

it = iter(function, sentinel) 

die == sentinelfunction() für jede Iteration Schritt, bis das Ergebnis nennt.

Wählen Sie also einen Sentinel, der von Ihrer gewünschten Funktion nie zurückgegeben werden kann, wie None, in Ihrem Fall.

rand_iter = lambda start, end: iter(random.randint(start, end), None) 
rand_bytes = rand_iter(0, 256) 

Wenn Sie einige Zustand auf Ihrem Computer überwachen möchten, können Sie tun

iter_mystate = iter(getstate, None) 

, die wiederum unendlich getstate() für jeden Iterationsschritt aufruft.

Aber Vorsicht bei Funktionen, die None als gültigen Wert zurückgeben! In diesem Fall sollten Sie einen Wächter wählen, die einzigartig sein wird garantiert, vielleicht ein Objekt für genau diesen Job erstellt:

iter_mystate = iter(getstate, object()) 
+2

Der einfachste zu verwendende Sentinel ist wahrscheinlich nur 'object()' –

+0

@ JonClements Sie haben Recht; Ich wollte nur vermeiden, unnötige Objekte zu erstellen. Aber wenn Sie es brauchen, weil Ihre Funktion legitimerweise 'None' zurückgibt, sollten Sie tatsächlich' object() 'verwenden. – glglgl

8

Jedes Mal, wenn ich iter mit 2 Argumenten zu sehen, muß ich meinen Kopf kratzt einen aufblick die Dokumentation, um genau herauszufinden, was vor sich geht. Ganz einfach, weil der, dass, würde ich wahrscheinlich meine eigene Rolle:

def call_forever(callback): 
    while True: 
     yield callback() 

Oder, wie es in den Kommentaren von Jon Clements erklärt, könnten Sie die itertools.repeatfunc Rezept verwenden, die Sie Argumente für die Funktion als auch passieren lässt :

import itertools as it 
def repeatfunc(func, times=None, *args): 
    """ 
    Repeat calls to func with specified arguments. 
    Example: repeatfunc(random.random) 
    """ 
    if times is None: 
     return it.starmap(func, it.repeat(args)) 
    return it.starmap(func, it.repeat(args, times)) 

Obwohl ich glaube, dass die Funktion Unterschrift def repeatfunc(func,times=None,*args) ein wenig umständlich ist. Ich würde es vorziehen, ein Tupel als args passieren (es scheint, noch deutlicher zu mir, und „explizite ist besser als implizite“):

import itertools as it 
def repeatfunc(func, args=(),times=None): 
    """ 
    Repeat calls to func with specified arguments. 
    Example: repeatfunc(random.random) 
    """ 
    if times is None: 
     return it.starmap(func, it.repeat(args)) 
    return it.starmap(func, it.repeat(args, times)) 

, die es ermöglicht, wie genannt werden:

repeatfunc(func,(arg1,arg2,...,argN),times=4) #repeat 4 times 
repeatfunc(func,(arg1,arg2,...))    #repeat infinitely 

anstelle der Vanille-Version von itertools:

repeatfunc(func,4,arg1,arg2,...) #repeat 4 times 
repeatfunc(func,None,arg1,arg2,...) #repeat infinitely 
+2

Und die andere Option ist möglicherweise das 'itertools.repeatfunc' Rezept ... –

+0

@ JonClements - Danke dafür. Ich habe meinen Beitrag aktualisiert. – mgilson

Verwandte Themen