2015-07-15 3 views
5

Anhand der folgenden als Beispiel können wir sehen, x.giveMyNum() wird 4 mal aufgerufen - 3 mal, um den Wert von myNum zu überprüfen und einmal, um die Liste zu erstellen, zurückzukehren. Sie möchten wahrscheinlich, dass es nur 3 Mal aufgerufen wird, da es sich um eine reine Funktion handelt, deren Wert sich nicht ändert.Verhindern mehrerer Aufrufe im Listenverständnis

Listenkomprehension Version:

class test(object): 
    def __init__(self,myNum): 
     self.myNum=myNum 
    def giveMyNum(self): 
     print "giving" 
     return self.myNum 
q=[test(x) for x in range(3)] 
print [x.giveMyNum() for x in q if x.giveMyNum()>1] 

Ich weiß, dass Sie etwas tun können, es zu beheben:

ret=[] 
for x in q: 
    k=x.giveMyNum() 
    if k>1: 
     ret.append(k) 

aber ist es eine Möglichkeit, den zusätzlichen Anruf in einer Liste Verständnis zu verhindern?

Ich brauche nicht den Zwischenwert zu halten.

Antwort

3

Sie können es mit einem Generator kombinieren, aber ich würde mit einer regelmäßigen Schleife bleiben.

print([n for n in (x.giveMyNum() for x in q) if n > 1 ]) 

Wenn Sie Funktionscode wie könnten Sie Karte oder itertools.imap mit python2:

print([n for n in map(test.giveMyNum, q) if n > 1 ]) 

Mit python2 und imap ist schneller als die gen exp:

In [8]: q = [test(x) for x in range(10000)] 

In [9]: timeit [ n for n in imap(test.giveMyNum, q) if n > 1] 
1000 loops, best of 3: 1.94 ms per loop 

In [10]: timeit [n for n in (x.giveMyNum() for x in q) if n > 1 ] 
100 loops, best of 3: 2.56 ms per loop 

Karte ist auch schneller mit python3:

In [2]: timeit [ n for n in map(test.giveMyNum, q) if n > 1] 
100 loops, best of 3: 2.23 ms per loop 

In [3]: timeit [n for n in (x.giveMyNum() for x in q) if n > 1 ] 
100 loops, best of 3: 2.93 ms per loop 

Der Zeitpunkt für die regelmäßige Schleife und Aufruf der Methode:

In [8]: timeit [x.giveMyNum() for x in q if x.giveMyNum()>1] 
100 loops, best of 3: 3.59 ms per loop 

In [9]: %%timeit 
ret=[] 
for x in q: 
    k=x.giveMyNum() 
    if k>1: 
     ret.append(k) 
    ...: 
100 loops, best of 3: 2.67 ms per loop 

Python3:

In [2]: %%timeit 
ret=[] 
for x in q: 
    k=x.giveMyNum() 
    if k>1: 
     ret.append(k) 
    ...: 
100 loops, best of 3: 2.84 ms per loop 

In [3]: timeit [x.giveMyNum() for x in q if x.giveMyNum()>1] 

100 loops, best of 3: 4.08 ms per loop 
+0

Ich mag Funktionscode. Das ist sehr gut lesbar. – Carbon

+0

@ProbablyAStupidQuestion, dann magst du 'filter (lambda n: n> 1, Karte (test.giveMyNum, q)))') –

+0

das ist wirklich nett! Ich bin traurig, Filter wird in Itertools in Python3 verschoben. – Carbon

3

Es ist möglich, aber nicht sehr gut lesbar ...

print [y for y in (x.giveMyNum() for x in q) if y > 1] 

so, es sei denn giveMyNum() ist langsam oder nicht rein, ich würde es vermeiden.

+0

Das ist genial - ein Generator Verständnis! Das ist wirklich schlau. Ich habe gefragt, weil ich einen Fall mit einer langsamen reinen Funktion habe und das löst das auf eine nette Art und Weise. – Carbon