¿Meexplican los paquetes?

Chema Cortés py en ch3m4.org
Lun Dic 22 02:32:29 CET 2003


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

El Sábado, 20 de Diciembre de 2003 00:37, Luis Rodrigo Gallardo Cruz escribió:

> Tengo una jerarquía de archivos como sigue:
>
>  tst/
>     __init__.py
>     db/
>       __init__.py
>       Propiedad.py
>
>  tst/__init__.py
> y
>  tst/db/Propiedad.py
> están vacios.
>
>  tst/db/__init__.py
> tiene el siguiente contenido:
>
>  import tst.db.Propiedad
>  a = tst.db.Propiedad
>
> Si desde el directorio que contiene todo esto arranco python (2.2 o
>
> 2.3) pasa lo siguiente:
> >>> import tst.db
>
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "tst/db/__init__.py", line 3, in ?
>     a = tst.db.Propiedad
> AttributeError: 'module' object has no attribute 'db'
>
> Fijense como el 'import tst.db.Propiedad' funcionó, por que el error
> me lo da en la siguiente linea.

No es del todo así como piensas. Cambia el __init__.py por lo siguiente, y 
veras que falla también el 'import':

import tst.db.Propiedad as MiPropiedad
a = MiPropiedad

¿Qué está ocurriendo?
Es algo complejo de explicar, pero voy a intentarlo.


>>> import tst.db

Este 'import' intenta, por orden, importar 'tst' y 'tst.db'. El módulo 'tst' 
lo importa sin problema, pero cuando importa 'tst.db' se encuentra que en la 
inicialización del módulo tiene un nuevo import:

import tst.db.Propiedad

Tiene que importar, por orden, 'tst', 'tst.db' y 'tst.db.Propiedad'. Aunque 
intuitivamente pensamos en estos módulos como referencia globales, desde el 
punto de vista de la importación no hay forma de distinguir entre módulos 
globales y locales, o lo que es lo mismo, no puede saber si el 'tst' se 
refiere al módulo padre o a un módulo local del mismo nombre. Para el 
'import' los módulos a importar podrían corresponder a las referencias 
globales 'tst.db.tst', 'tst.db.tst.db' y 'tst.db.tst.db.Propiedad', 
respectivamente.

Para evitar esto, en el caché de módulos se incluyen una referencias 
"señuelos" ("dummies") que engañan al proceso de importación para que no 
intente importar como locales algunos módulos globales.

Si vemos detenidamente lo que hay en el 'sys.modules' vemos ésto:

 'tst': <module 'tst' from 'tst/__init__.py'>,
 'tst.db': <module 'tst.db' from 'tst/db/__init__.py'>,
 'tst.db.Propiedad': <module 'tst.db.Propiedad' from 'tst/db/Propiedad.py'>,
 'tst.db.tst': None,

Esta última referencia "señuelo" es la que engaña al import para que crea que 
el módulo global 'tst', que está viendo como 'tst.db.tst', figure como ya 
importado.

Hago un inciso para explicar que el mecanismo de optimización de importación 
de módulos (del que alguna vez hemos hablado por aquí) es el que hace que no 
se vuelva a importar módulos que estaban ya importados. Si un módulo figura 
entre los módulos importados ('sys.modules') en lugar de volver a importarlo 
se copia su referencia.

Cuando haces el 'import tst.db.Propiedades' el mecanismo de importación ve que 
ya tiene importado el módulo local 'tst' (='tst.db.tst'). El problema es que 
al querer importar luego el 'tst.db' (='tst.db.tst.db') falla porque 
'tst' (='tst.db.tst') era un señuelo.

No se si me he explicado, ya que también a mí me cuesta entenderlo.

La solución al problema pasa por no utilizar referencias a submódulos que 
incluyan explícitamente la jerarquía de módulos del paquete, y dejar así que 
el mecanismo de importación devuelva la referencia correcta.

En general, es muy recomendable que en lugar de

  import tst.db.Propiedad
  a=tst.db.Propiedad

se haga siempre

  from tst.db import Propiedad
  a=Propiedad


Hay un viejo ensayo de Guido que explica algo de todo ésto:
http://www.python.org/doc/essays/packages.html


- -- 
Chema Cortes (py en ch3m4.org)
  http://py.ch3m4.org
    PGPKEY: mailto:pgpkey en ch3m4.org?subject=__PGPKEY__

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)

iD8DBQE/5kmzHLTQrABk8H0RArA6AJ4r1fg28yD3TB6XPXWik49ziPKwDwCfX0d1
9KwYHzYIm/47sMAqLd1oW7A=
=WWYT
-----END PGP SIGNATURE-----




Más información sobre la lista de distribución Python-es