Capítulo 5. Objetos y orientación a objetos

Este capítulo, y básicamente todos los que le siguen trabajan con programación en Python orientada a objetos.

5.1. Inmersión

Aquí tiene un programa en Python completo y funcional. Lea las cadenas de documentación del módulo, las clases, y las funciones para obtener una idea general de lo que hace el programa y cómo funciona. Como de costumbre, no se preocupe por lo que no entienda; para eso está el resto del capítulo.

Ejemplo 5.1. fileinfo.py

Si aún no lo ha hecho, puede descargar éste ejemplo y otros usados en este libro.

"""Infraestructura para obtener metadatos específicos por tipo de fichero.

Instancie la clase apropiada con el nombre del fichero. El objeto
devuelto actúa como un diccionario, con pares clave-valor por cada
metadato.
    import fileinfo
    info = fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")
    print "\\n".join(["%s=%s" % (k, v) for k, v in info.items()])

O use la función listDirectory para obtener información de todos los
ficheros en un directorio.
    for info in fileinfo.listDirectory("/music/ap/", [".mp3"]):
        ...

Se puede extender esta infraestructura añadiendo clases para tipos
particulares de fichero, por ejemplo HTMLFileInfo, MPGFileInfo,
DOCFileInfo. Cada clase es completamente responsable de analizar sus
ficheros adecuadamente; vea MP3FileInfo si desea un ejemplo.
"""
import os
import sys
from UserDict import UserDict

def stripnulls(data):
    "strip whitespace and nulls"
    return data.replace("\00", "").strip()

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

class MP3FileInfo(FileInfo):
    "store ID3v1.0 MP3 tags"
    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):
        "parse ID3v1.0 tags from MP3 file"
        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):                                        
    """obtener lista de objetos de información sobre ficheros de
extensiones particulares"""
    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__]):      
        "obtener la clase de información de un fichero por su extensión"                             
        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 La salida de este programa depende de los ficheros de su disco duro. Para obtener una salida con sentido, necesitará cambiar la ruta de directorio para que apunte a uno que contenga ficheros MP3 en su propia máquina.

Ésta es la salida que obtengo en mi máquina. La de usted puede diferir, a menos que, por alguna sorprendente coincidencia, tenga exactamente mis mismos gustos musicales.

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