Zanurkuj w Pythonie/Wyjątki i operacje na plikach - wszystko razem: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
zamiana {{Nawigacja|Python|->{{Nawigacja|Zanurkuj w Pythonie| [[Python/->[[../
Piotr (dyskusja | edycje)
poprawki
Linia 1:
{{Podświetl|py}}
== Wszystko razem ==
 
Jeszcze raz ułożymy wszystkie klockipuzlle domina w jednym miejscu. Już wcześniej poznaliśmy, w jaki sposób działa każda linia kodu. Teraz znowuPowrócimy do tego powrócimyjeszcze raz i zobaczymy, jak to wszystko jest ze sobą dopasowane.
 
'''{{Python/Przykład 6.21. listDirectory'''
|6.21|<code>listDirectory</code>
def listDirectory(directory, fileExtList): #(1)
|tekst=
"get list of file info objects for files of particular extensions"
<nowiki>def listDirectory(directory, fileExtList): #(1)
fileList = [os.path.normcase(f)
u"zwraca listę obiektów zawierających metadane dla plików o podanych rozszerzeniach"
for f in os.listdir(directory)]
fileList = [os.path.joinnormcase(directory, f) for f in os.listdir(directory)]
fileList = [os.path.join(directory, f) for f in fileList
if os.path.splitext(f)[1] in fileExtList] #(2)
def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]): #(3)
u"zwraca klasę metadanych pliku na podstawie podanego rozszerzenia"
"get file info class from filename extension"
subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:] #(4)
return hasattr(module, subclass) and getattr(module, subclass) or FileInfo #(5)
return [getFileInfoClass(f)(f) for f in fileList] #(6)</nowiki>
 
# <ttcode>listDirectory</ttcode> jest główną atrakcją tego modułu. Przyjmuje ona na wejściu folderkatalog (np. <tt class="lang-none">c:\music\_singles\</tt>) i listę interesujących nas rozszerzeń plików (jak np. <ttcode>['.mp3']</ttcode>), a następnie zwraca listę instancji klas, które działają podobnie jakpodklasami słownikisłownika, a przechowują metadane na temat każdego interesującego nas pliku w tym katalogu. I to wszystko jest wykonywane za pomocą kilku prostych linii kodu.
# Jak dowiedziałeśdowiedzieliśmy się w [[../Praca z katalogami|poprzednim rozdzialepodrozdziale]], ta linia kodu zwraca listę pełnych ścieżek wszystkich plików z folderudanego katalogu, które mają interesujące nas rozszerzenie (podane w argumencie <ttcode>fileExtList</ttcode>).
# Starzy programiści Pascala znają zagnieżdżone funkcje (funkcje wewnątrz funkcji), ale większość ludzi jest zdziwionych, gdy mówięmówi się im, że Python je wspiera. Zagnieżdżona funkcja <ttcode>getFileInfoClass</ttcode> może być wywołana tylko z funkcji, w której jest zadeklarowana, --czyli z <ttcode>listDirectory</ttcode>. Jak w przypadku każdej innej funkcji, nie musiszmusimy przejmować się deklaracją interfejsu, ani niczym innym. Po prostu zdefiniujdefiniujemy funkcję i napisz jejimplementujamy ciało.
# Teraz, gdy już znaszznamy moduł <ttcode>os</ttcode>, ta linia powinna nabrać sensu. Pobiera ona rozszerzenie pliku (<ttcode>os.path.splitext(filename)[1]</ttcode>), przekształca je do dużych liter (<ttcode>.upper()</ttcode>), odcina kropkę (<ttcode>[1:]</ttcode>) i tworzy nazwę klasy używając stringułańcucha formatującego. <tt>c:\music\ap\mahadeva.mp3</tt> stajezostaje sięprzekształcone więcna <tt>.mp3</tt>, potem na <tt>.MP3</tt>, a następnie na <tt>MP3</tt> i na końcu otrzymujemy <tt>MP3FileInfo</tt>.
# Mając nazwę klasy obsługującej ten plik, sprawdzamy czy tak klasa istnieje w tym module. Jeśli tak, zwracamy tę klasę, jeśli nie -- klasę bazową <ttcode>FileInfo</ttcode>. To bradzobardzo ważne: zwracamy klasę. Nie obiektzwracamy obiektu, ale klasę samą w sobie.
# Dla każdego pliku z listy <ttcode>fileList</ttcode> wołamywywołujemy <ttcode>getFileInfoClass</ttcode> z nazwą pliku <ttcode>(f)</ttcode>. Wywołanie <ttcode>getFileInfoClass(f)</ttcode> zwraca klasę. Dokładnie nie wiadomo jaką, ale to nam nie przeszkadza. Potem tworzymy obiekt tej klasy (jaka by ona nie była) i przekazujemy nazwę pliku (znów <ttcode>f</ttcode>) do jej metody <ttcode>__init__</ttcode>. Jak pamiętaszpamiętamy z [[../Metody specjalne|wcześniejszych rozdziałów]], metoda <ttcode>__init__</ttcode> klasy <ttcode>FIleInfoFileInfo</ttcode> ustawia wartość <ttcode>self["name"]</ttcode>, co powoduje wywołanie <ttcode>__setitem__</ttcode> klasy pochodnej, czyli <ttcode>MP3FileInfo</ttcode>, żeby odpowiednio przetworzyć plik i wyciągnąć jego metadane. Robimy to wszystko dla każdego interesującego pliku i zwracamy listę obiektów wynikowych.
}}
 
Zauważ, że metoda <tt>listDirectory</tt> jest bardzo ogólna. Nie wie w żaden sposób z jakimi typami plików będzie pracować ani jakie klasy są zdefiniowane do obsługi tych plików. Zaczyna pracę od przejrzenia folderu, w poszukiwaniu plików do przetwarzania a potem analizuje swój moduł żeby sprawdzić, jakie klasy obsługi (jak na przykład <tt>MP3FileInfo</tt>) są zdefiniowane. Możesz rozszerzyć ten program, żeby obsługiwać inne typy plików definiując klasy o odpowiednich nazwach: <tt>HTMLFileInfo</tt> dla plików HTML, <tt>DOCFileInfo</tt> dla plików Worda i tak dalej. <tt>listDirectory</tt> obsłuży je wszystkie bez modyfikacji, zrzucając całe przetwarzanie na odpowiednie klasy i zbierając wyniki.
 
ZauważZauważmy, że metoda <tt>listDirectory</tt> jest bardzo ogólna. Nie wie w żaden sposób, z jakimi typami plików będzie pracować, ani jakie klasy są zdefiniowane do obsługi tych plików. Zaczyna pracę od przejrzenia folderukatalogu, w poszukiwaniu plików do przetwarzania, a potem analizuje swój moduł, żeby sprawdzić, jakie klasy obsługi (jak na przykładnp. <ttcode>MP3FileInfo</ttcode>) są zdefiniowane. MożeszMożemy rozszerzyć ten program, żeby obsługiwać inne typy plików definiując klasy o odpowiednich nazwach: <ttcode>HTMLFileInfo</ttcode> dla plików HTML, <ttcode>DOCFileInfo</ttcode> dla plików Worda i tak dalejitp. <ttcode>listDirectory</ttcode>, bez potrzeby modyfikacji kodu tej funkcji, obsłuży je wszystkie bez modyfikacji, zrzucając całe przetwarzanie na odpowiednie klasy i zbierając otrzymane wyniki.
<noinclude>
{{Nawigacja|Zanurkuj w Pythonie|
[[../Praca z katalogami|Praca z katalogami/]]|
[[../Wyjątki_i_operacje_na_plikach_-_podsumowanie|Podsumowanie]]|
}}
{{Podświetl|py}}
</noinclude>