Zanurkuj w Pythonie/Obiekty i klasy

Rozdział ten zaznajomi nas ze zorientowanym obiektowo programowaniem przy użyciu języka Python.

Nurkujemy edytuj

Poniżej znajduje się kompletny program, który oczywiście działa. Czytanie notki dokumentacyjnej modułu, klasy, czy też funkcji jest pomocne w zrozumieniu co dany program właściwie robi i w jaki sposób działa. Jak zwykle, nie martwmy się, że nie możemy wszystkiego zrozumieć. W końcu zasada działania tego programu zostanie dokładnie opisana w dalszej części tego rozdziału.

Przykład. fileinfo.py
#-*- coding: utf-8 -*-

u"""Framework do pobierania metadanych specyficznych dla danego typu pliku.

Można utworzyć instancję odpowiedniej klasy podając jej nazwę pliku w konstruktorze.
Zwrócony obiekt zachowuje się jak słownik posiadający parę klucz-wartość
dla każdego fragmentu metadanych.

    import fileinfo
    info = fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")
    print "\\n".join(["%s=%s" % (k, v) for k, v in info.items()])

Lub użyć funkcji listDirectory, aby pobrać informacje o wszystkich plikach w katalogu.
    for info in fileinfo.listDirectory("/music/ap/", [".mp3"]):
        ...

Framework może być rozszerzony poprzez dodanie klas dla poszczególnych typów plików, np.:
HTMLFileInfo, MPGFileInfo, DOCFileInfo.  Każda klasa jest całkowicie odpowiedzialna
za właściwe sparsowanie swojego pliku; zobacz przykład MP3FileInfo.
"""

import os
import sys

def stripnulls(data):
    u"usuwa białe znaki i nulle"
    return data.replace("\00", " ").strip()

class FileInfo(dict):
    u"przechowuje metadane pliku"
    def __init__(self, filename=None):
        dict.__init__(self)
        self["plik"] = filename
    
class MP3FileInfo(FileInfo):
    u"przechowuje znaczniki ID3v1.0 MP3"
    tagDataMap = {u"tytuł"    : (  3,  33, stripnulls),
                  "artysta"   : ( 33,  63, stripnulls),
                  "album"     : ( 63,  93, stripnulls),
                  "rok"       : ( 93,  97, stripnulls),
                  "komentarz" : ( 97, 126, stripnulls),
                  "gatunek"   : (127, 128, ord)}
    
    def __parse(self, filename):
        u"parsuje znaczniki ID3v1.0 z pliku MP3"
        self.clear()
        try:
            fsock = open(filename, "rb", 0)
            try:
                fsock.seek(-128, 2)
                tagdata = fsock.read(128)
            finally:
                fsock.close()
            if tagdata[:3] == 'TAG':
                for tag, (start, end, parseFunc) in self.tagDataMap.items():
                    self[tag] = parseFunc(tagdata[start:end])
        except IOError:
            pass

    def __setitem__(self, key, item):
        if key == "plik" and item:
            self.__parse(item)
        FileInfo.__setitem__(self, key, item)

def listDirectory(directory, fileExtList):
    u"zwraca listę obiektów zawierających metadane dla plików o podanych rozszerzeniach"
    fileList = [os.path.normcase(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]
    def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):
        u"zwraca klasę metadanych pliku na podstawie podanego rozszerzenia"
        subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]
        return hasattr(module, subclass) and getattr(module, subclass) or FileInfo
    return [getFileInfoClass(f)(f) for f in fileList]

if __name__ == "__main__":
    for info in listDirectory("/music/_singles/", [".mp3"]):   #(1)
        print "\n".join("%s=%s" % (k, v) for k, v in info.items())
        print
  1. Wynik wykonania tego programu zależy od tego jakie pliki mamy na twardym dysku. Aby otrzymać sensowne wyjście, potrzebujemy zmienić ścieżkę, aby wskazywał na katalog, w którym przechowujemy pliki MP3.

W wyniku wykonania tego programu możemy otrzymać podobne wyjście do poniższego. Jest niemal niemożliwe, abyś otrzymał identyczne wyjście.

album=
rok=1999
komentarz=http://mp3.com/ghostmachine
tytuł=A Time Long Forgotten (Concept
artysta=Ghost in the Machine
gatunek=31
plik=/music/_singles/a_time_long_forgotten_con.mp3

album=Rave Mix
rok=2000
komentarz=http://mp3.com/DJMARYJANE
tytuł=HELLRAISER****Trance from Hell
artysta=***DJ MARY-JANE***
gatunek=31
plik=/music/_singles/hellraiser.mp3

album=Rave Mix
rok=2000
komentarz=http://mp3.com/DJMARYJANE
tytuł=KAIRO****THE BEST GOA
artysta=***DJ MARY-JANE***
gatunek=31
plik=/music/_singles/kairo.mp3

album=Journeys
rok=2000
komentarz=http://mp3.com/MastersofBalan
tytuł=Long Way Home
artysta=Masters of Balance
gatunek=31
plik=/music/_singles/long_way_home1.mp3

album=
rok=2000
komentarz=http://mp3.com/cynicproject
tytuł=Sidewinder
artysta=The Cynic Project
gatunek=18
plik=/music/_singles/sidewinder.mp3

album=Digitosis@128k
rok=2000
komentarz=http://mp3.com/artists/95/vxp
tytuł=Spinning
artysta=VXpanded
gatunek=255
plik=/music/_singles/spinning.mp3