¿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