2009-12-02 16 views
9

I często napisać kod jak:Jak czysto pętli nad dwoma plikami równolegle w Pythonie

lines = open('wordprob.txt','r').readlines() 
words = open('StdWord.txt','r').readlines() 
i = 0 
for line in lines: 
    v = [eval(s) for s in line.split()] 
    if v[0] > v[1]: 
     print words[i].strip(), 
    i += 1 

to możliwe, aby uniknąć użycia zmiennej I i uczynić program krótszy?

Dzięki.

Odpowiedz

14

Można spróbować użyć wyliczyć,

http://docs.python.org/tutorial/datastructures.html#looping-techniques

lines = open('wordprob.txt','r').readlines() 
words = open('StdWord.txt','r').readlines() 
for i,line in enumerate(lines): 
     v = [eval(s) for s in line.split()] 
     if v[0] > v[1]: 
       print words[i].strip() 
+5

Nie podoba mi się to rozwiązanie, ponieważ odczytuje wszystkie dane do pamięci RAM. Jest to w porządku, o ile dane mieszczą się w pamięci RAM, i jest to proste, ale wolę ogólne rozwiązania, które działają na dowolnym zestawie danych o rozmiarze. – steveha

1

Spójrz na enumerate:

>>> for i, season in enumerate(['Spring', 'Summer', 'Fall', 'Winter']): 
...  print i, season 
0 Spring 
1 Summer 
2 Fall 
3 Winter 
5

W ogólnym enumerate jest dobrym rozwiązaniem. W tym przypadku, można zrobić coś takiego:

lines = open('wordprob.txt','r').readlines() 
words = open('StdWord.txt','r').readlines() 
for word, line in zip(words, lines): 
    v = [eval(s) for s in line.split()] 
    if v[0] > v[1]: 
      print word.strip(), 
+4

'zip()' to dobry sposób na zapętlenie dwóch rzeczy razem. Jednak w Pythonie 2.x zbuduje listę ze wszystkimi wartościami, więc zajmie to dużo pamięci. Możesz uzyskać ten sam efekt za pomocą 'itertools.izip()', który zwraca iterator, który zwraca wartości po jednej na raz. Możesz 'import itertools', a następnie wykonaj to:' dla słowa, linii w itertools.izip (otwórz ('wordprob.txt'), otwórz ('StdWord.txt')): ' – steveha

+0

@steveha: Alternatywnie, ty wybierasz do wersji Py3 funkcji, wykonując 'from future_builtins import map, filter, zip' i zastępujesz wersje Py2 wersjami opartymi na iteratorze Py3. – ShadowRanger

20

Wygląda na to, że nie obchodzi mnie, co wartość i jest. Po prostu używasz go jako sposobu na powiązanie lines i words. Dlatego polecam przeczytać jedną linię na raz, a jednocześnie przeczytać jedno słowo. Wtedy się dopasują.

Ponadto, gdy używasz .readlines(), wszystkie dane wejściowe są od razu zapisywane w pamięci. W przypadku dużych wejść będzie to powolne. Dla tego prostego kodu wystarczy jedna linia na raz. Obiekt pliku zwrócony przez open() może działać jako iterator, który zwraca jedną linię na raz.

Jeśli możesz, powinieneś unikać używania eval(). W prostym ćwiczeniu, w którym wiesz, jakie dane wejściowe będą, jest to całkiem bezpieczne, ale jeśli otrzymasz dane ze źródeł zewnętrznych, użycie eval() może pozwolić na atak komputera. Aby uzyskać więcej informacji, patrz this page. Napiszę przykładowy kod, aby założyć, że używasz eval() do zamiany tekstu na wartość float. float() będzie działać również na wartości liczb całkowitych: float('3') zwróci 3.0.

Wygląda na to, że linie wejściowe mogą mieć tylko dwie wartości. Jeśli linia ma dodatkowe wartości, twój kod nie wykryje tego stanu. Możemy zmienić kod, aby jawnie rozpakować dwie wartości z linii podziału, a jeśli są więcej niż dwie wartości, Python zgłosi wyjątek. Dodatkowo kod będzie nieco ładniejszy do odczytania.

Więc tutaj jest moja sugerowana przepisać tego przykładu:

lines = open('wordprob.txt','rt') 
words = open('StdWord.txt','rt') 

for line in lines: 
    word = words.next().strip() # in Python 3: word = next(words).strip() 
    a, b = [float(s) for s in line.split()] 
    if a > b: 
     print word, # in Python 3: print(word + ' ', end='') 

EDIT: I tu jest to samo rozwiązanie, ale przy użyciu izip().

import itertools 
lines = open('wordprob.txt','rt') 
words = open('StdWord.txt','rt') 

# in Python 3, just use zip() instead of izip() 
for line, word in itertools.izip(lines, words): 
    word = word.strip() 
    a, b = [float(s) for s in line.split()] 
    if a > b: 
     print word, # in Python 3: print(word + ' ', end='') 

W Pythonie 3, wbudowany zip() zwraca iterator, więc można po prostu użyć tego i nie trzeba import itertools.

EDYTOWANIE: Najlepiej jest użyć instrukcji with, aby upewnić się, że pliki są poprawnie zamknięte, bez względu na wszystko. W najnowszych wersjach Pythona możesz mieć wiele z instrukcjami, a zrobię to w moim rozwiązaniu.Możemy również rozpakować wyrażenie generujące tak samo łatwo, jak możemy rozpakować listę, więc zmieniłem linię, która ustawia a, b, aby użyć wyrażenia generatora; to powinno być nieco szybsze. I nie musimy rozbierać word, chyba że będziemy z niego korzystać. Połącz zmiany, aby uzyskać:

from itertools import izip 

with open('wordprob.txt','rt') as lines, open('StdWord.txt','rt') as words: 
    # in Python 3, just use zip() instead of izip() 
    for line, word in izip(lines, words): 
     a, b = (float(s) for s in line.split()) 
     if a > b: 
      print word.strip(), # in Python 3: print(word.strip() + ' ', end='') 
+0

dzięki za cenne uwagi! –

+0

Serdecznie witamy! :-) – steveha

Powiązane problemy