Глава 3. Средства объектно-ориентированного программирования

Содержание

3.1. В глубь

Начиная с этой главы мы будем иметь дело с объектно ориентированным программированием на языке Python. Помните, я говорил, что вам необходимо знать объектно-ориентированный язык для чтения этой книги? Так я не шутил.

Здесь приведена полноценная программа на языке Python. Прочитайте строки документации модуля, классов и функций для полуения информации о том, что программа делает и как она работает. Как обычно, не обеспокойтесь, если что-либо вы не понимаете: для этого и предназначена оставшаяся часть главы.

Пример 3.1. fileinfo.py

Если вы еще этого не сделали, можете загрузить этот и другие примеры, используемые в книге.

"""Получение метаинформации, специфичной для файла данного типа.

Создайте экземпляр соответствующего класса, передав конструктору имя файла.
Возвращаемый объект ведет себя аналогично словарю с парами ключ-значение для
каждой части метаинформации.
    import fileinfo
    info = fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")
    print "\\n".join(["%s=%s" % (k, v) for k, v in info.items()])

Или используйте функцию listDirectory для получения информации обо всех файлов
в директории
    for info in fileinfo.listDirectory("/music/ap/", [".mp3"]):
        ...

Модуль может быть расширен путем доюавления классов для других типов файлов,
например HTMLFileInfo, MPGFileInfo, DOCFileInfo.  Каждый класс полностью
отвечает за анализ файлов соответствующего типа; используйте MP3FileInfo в
качестве примера.
"""
import os
import sys
from UserDict import UserDict

def stripnulls(data):
    "очищает строку от символов пропуска и нулевых символов"
    return data.replace("\00", "").strip()

class FileInfo(UserDict):
    "хранит метаинформацию о файле"   
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

class MP3FileInfo(FileInfo):
    "хранит ID3v1.0 MP3 теги"
    tagDataMap = {"title"   : (  3,  33, stripnulls),
                  "artist"  : ( 33,  63, stripnulls),
                  "album"   : ( 63,  93, stripnulls),
                  "year"    : ( 93,  97, stripnulls),
                  "comment" : ( 97, 126, stripnulls),
                  "genre"   : (127, 128, ord)}

    def __parse(self, filename):
        "анализ ID3v1.0 тегов из 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 == "name" and item:
            self.__parse(item)
        FileInfo.__setitem__(self, key, item)

def listDirectory(directory, fileExtList):                                        
    """возвращает список объектов с метаинформацией для всех файлов с
указанным расширением"""                       
    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__]):      
        "оределяет класс, предназначеный для обработки файла, по расширению"      
        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 Вывод этой программы зависит от файлов на вашем диске. Чтобы получить осмысленную информацию, необходимо изменить путь на каталог, содержащий MP3 файлы на вашей машине.

Пример 3.2. Вывод программы fileinfo.py

Вот результат, полученный на моей машине. Ваш результат будет другим, если только ваши музыкальные вкусы полность не совпадают с моими.

album=
artist=Ghost in the Machine
title=A Time Long Forgotten (Concept
genre=31
name=/music/_singles/a_time_long_forgotten_con.mp3
year=1999
comment=http://mp3.com/ghostmachine

album=Rave Mix
artist=***DJ MARY-JANE***
title=HELLRAISER****Trance from Hell
genre=31
name=/music/_singles/hellraiser.mp3
year=2000
comment=http://mp3.com/DJMARYJANE

album=Rave Mix
artist=***DJ MARY-JANE***
title=KAIRO****THE BEST GOA
genre=31
name=/music/_singles/kairo.mp3
year=2000
comment=http://mp3.com/DJMARYJANE

album=Journeys
artist=Masters of Balance
title=Long Way Home
genre=31
name=/music/_singles/long_way_home1.mp3
year=2000
comment=http://mp3.com/MastersofBalan

album=
artist=The Cynic Project
title=Sidewinder
genre=18
name=/music/_singles/sidewinder.mp3
year=2000
comment=http://mp3.com/cynicproject

album=Digitosis@128k
artist=VXpanded
title=Spinning
genre=255
name=/music/_singles/spinning.mp3
year=2000
comment=http://mp3.com/artists/95/vxp