2012-06-19 20 views
8

Mam listę obiektów:Tworzenie listy atrybutów obiektu w Pythonie

[Object_1, Object_2, Object_3] 

Każdy obiekt ma atrybut: Godzina:

Object_1.time = 20 
Object_2.time = 30 
Object_3.time = 40 

Chcę utworzyć listę atrybutów czas:

[20, 30, 40] 

Jaki jest najbardziej wydajny sposób uzyskania tego wyniku? To nie może być iteracyjne nad listy obiektów, prawda ?:

items = [] 
for item in objects: 
    items.append(item.time) 
+0

"Skuteczny" jest w oku patrzącego ... –

+1

@Pyson: Nie, nie jest, "efektywny" jest mierzony w złożoności, czasie obliczeń, liniach kodu i/lub pamięci. – Junuxx

+4

@Junuxx: większość ludzi nie testuje każdego wystąpienia zrozumienia względem pętli, aby zobaczyć, która jest mniejsza liczba cykli procesora. Jeśli korzystasz z Pythona, prawdopodobnie chodzi o łatwość pisania i czytania - a nie bezwzględną szybkość. To, co tam napisałeś, czas obliczeń, linie kodu i/lub użycie pamięci, mogą być całkowicie sprzeczne. Podwójny kod może być szybszy i zużywa mniej pamięci, ale zajmuje więcej czasu, aby czytać i pisać jako programista. Który jest bardziej * wydajny *? Szybciej wykonać lub szybciej pisać w Pythonie? To jest mój punkt widzenia. –

Odpowiedz

23

Lista jest zrozumienie tego, co jesteś po:

list_of_objects = [Object_1, Object_2, Object_3] 
[x.time for x in list_of_objects] 
+0

Należy zauważyć, że jest to tak samo skuteczne, jak kod OP. – Marcin

+0

@Marcin: W rzeczywistości, nie ma gwarancji, że listy są zrozumiałe zarówno w równym, większym, jak i mniejszym stopniu niż odpowiadające im listy. Oczywiście, możesz znaleźć odpowiedź, czytając kod CPython (lub wątki listy dyskusyjnej od kiedy zaproponowano listę), ale czy możesz przyjąć, że dotyczyłoby to, powiedzmy, PyPy? Lepiej więc powiedzieć, że nie ma powodu, by sądzić, że będzie to bardziej efektywne. – abarnert

+4

Co? Tak jest. Pętla ze zrozumieniem listy jest wykonywana po stronie C, która jest znacznie szybsza niż pętla w języku Python.Każda implementacja będzie szybsza, ponieważ zrozumienie list jest mniej ekspresyjną rzeczą, a zatem można ją zoptymalizować bardziej efektywnie. –

2

Jak o:

items=[item.time for item in objects] 
2
from operator import attrgetter 
items = map(attrgetter('time'), objects) 
+1

Zwróć uwagę, że mapa zwraca generator, a nie listę w 3.x, i że zrozumienie list jest o wiele bardziej czytelne (i prawdopodobnie szybsze) w przypadku czegoś takiego. –

+2

@Uprawione oprogramowanie: +1. A jeśli faktycznie chcesz być generatorem, możesz użyć wyrażenia generatora równie łatwo, jak ze zrozumieniem listy. – abarnert

2

Najszybszym (i najłatwiejszym do zrozumienia) jest ze zrozumieniem listy.

Zobacz taktowania:

import timeit 
import random 
c=10000 

class SomeObj: 
    def __init__(self, i): 
     self.attr=i 

def loopCR(): 
    l=[] 
    for i in range(c): 
     l.append(SomeObj(random.random())) 

    return l 

def compCR(): 
    return [SomeObj(random.random()) for i in range(c)] 

def loopAc(): 
    lAttr=[] 
    for e in l: 
     lAttr.append(e.attr) 

    return lAttr 

def compAc(): 
    return [e.attr for e in l]    

t1=timeit.Timer(loopCR).timeit(10) 
t2=timeit.Timer(compCR).timeit(10) 
print "loop create:", t1,"secs" 
print "comprehension create:", t2,"secs" 
print 'Faster of those is', 100.0*abs(t1-t2)/max(t1,t2), '% faster' 
print 

l=compCR() 

t1=timeit.Timer(loopAc).timeit(10) 
t2=timeit.Timer(compAc).timeit(10) 
print "loop access:", t1,"secs" 
print "comprehension access:", t2,"secs" 
print 'Faster of those is', 100.0*abs(t1-t2)/max(t1,t2), '% faster' 

Drukuje:

loop create: 0.103852987289 secs 
comprehension create: 0.0848100185394 secs 
Faster of those is 18.3364670069 % faster 

loop access: 0.0206878185272 secs 
comprehension access: 0.00913000106812 secs 
Faster of those is 55.8677438315 % faster 

więc lista jest zarówno zrozumienie szybciej pisać i szybsze do wykonania.