Desimportar modulos

Chema Cortés py en ch3m4.org
Jue Sep 25 00:14:42 CEST 2003


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

El Miércoles, 24 de Septiembre de 2003 18:24, AcrraidX escribió:

> BUeno..., el problema que mencionas tiene relación precisamente con lo que
> estoy haciendo. Hay varios servidores de bases de datos a los que el
> programilla accederá, algunos son servidores postgresql y o tros son mysql.
> Aveces hay que acceder a los servidores de DB mysql y otras veces a los
> postgresql. La implementación de estos servidores dependen de sus
> respectivos sysop's. El detalle era cargar los modulos de postgresql cuando
> se accedan a los servidores postgresql y si por alguna razón (depende del
> usuario del programilla) se debe acceder a los servidores mysql descargar
> el módulo de postgresql y cargar el de mysql, es decir, cuando se accede a
> una base de datos no se necesita en ese instante el módulo que sirve para
> conectarse a la otra base de datos. Aunque creo, justamente en este
> instante, que eso podría arreglarse con una simple instrucción 'if' de
> terminando con esta cuál módulo importar..., pero de todas formas tenía la
> curiosidad de saber si se podía descargar un módulo, pero creo ahorita que
> es mejor dejárselo al colector de basura de python.

Este mismo problema está implícito con el módulo 'os'. Según la plataforma 
donde se ejecute, se cargará un módulo 'os' diferente.

Contestando también a José Antonio Díez, la manera más elegante para decidir 
el módulo a importar es utilizar el 'import...as...' ó, equivalentemente, la 
función __import__ :


MODULO='MySQLdb'
#MODULO='psycopg'

dbmod=__import__(MODULO)  #equivalente a 'import MODULO as dbmod'


if dbmod.__name__=="MySQLdb":
  print "Estoy utilizando MySQL"

  con=dbmod.connect(db="test",host="localhost")
else:
  ...

cur=con.cursor()
...
...

con.close()
del con
del dbmod   #borrada la referencia al módulo


Con el último 'del' se elimina la referencia al módulo para, si es posible, se 
libere la memoria ocupada en el siguiente ciclo del 'gc'.

Esto no quiere decir que tengamos que preocuparnos de ir siempre borrando las 
variables para liberar memoria. Lo normal y recomendable es utilizar siempre 
que se pueda variables locales de modo que, una vez fuera del scope donde 
habían sido definidas, se autoliberen todas las referencias que hayamos hecho 
(a esto me refería por ser "ecológico", a conservar el espacio global de 
nombres).

Pero el proceso es más complejo de lo que podemos suponer ya que el intérprete 
optimiza la creación/destrucción de objetos a costa de utilizar más memoria. 
Hay objetos que no desaparecen de la memoria por mucho que los borres. Una 
forma de averiguar lo que está pasando es utilizar la función id(). Si dos 
objetos tienen el mismo id, es que ambos son el mismo.

Al arrancar un intérprete de python se inician algunos objetos tales como los 
enteros desde el -1 al 99, los booleanos True y False, los conjuntos vacíos 
[] () y {} , etc.:

>>> a=1
>>> b=1
>>> id(a),id(b)
(135467576, 135467576)
>>> del a, b
>>> c=1
>>> id(c)
135467576

>>> a=1000
>>> b=1000
>>> id(a),id(b)
(135618184, 135618172)


Para las cadenas de caracteres existe una "pool" (traducción: "reserva") donde 
se van guardando las cadenas para su reutilización. Este mecanismo se ideó 
para optimizar el manejo de nombre de variables, por lo que se puede observar 
que toda cadena de una sóla palabra acabará automáticamente en este "pool" y 
siempre será reutilizada (y por lo tanto, siempre estará en memoria):

>>> a="Hola"
>>> b="Hola"
>>> id(a),id(b)
(1076941536, 1076941536)
>>> a="Hola, mundo"
>>> b="Hola, mundo"
>>> id(a),id(b)
(1076911424, 1076911384)


Si queremos que una cadena cualquiera se meta en el "pool" de cadenas (por 
ejemplo, porque esperamos utilizarla en muchas ocasiones) podemos utilizar la 
función 'intern':

>>> a="Hola, mundo"
>>> b="Hola, mundo"
>>> id(a),id(b)
(1076728160, 1076729240)
>>> a=intern("Hola, mundo")
>>> b=intern("Hola, mundo")
>>> id(a),id(b)
(1076825088, 1076825088)

No es raro que se denomine al proceso de meter una cadena en el "pool" de 
cadenas como de "internar" la cadena.


Para módulos (que de eso iba la cuestión :-P) también existe un "pool", de 
modo que el import mira primero en esta "pool" antes de cargar el módulo del 
disco. Para saber los módulos que están cargados:

import sys
print sys.modules.keys()

Podemos ver que hay bastantes módulos pre-cargados, por ejemplo 'sys' (ya 
estaba antes de hacer nosotros el import) ó el 'zipimport' que necesita el 
import para tratar módulos en formato zip (v2.3).

Con el 'sys' hay una curiosidad y es que el módulo que importamos ha sido 
manipulado durante la inicialización (se ha eliminado el acceso a la función 
'sys.setdefaultenconding'). Si queremos volver a la versión original guardada 
en disco hay que utilizar 'reload(sys)'.

Es complicado saber qué módulos necesitamos que estén cargados. Tan sólo 
podemos confiar en el buen hacer del gc para libere toda la memoria que sea 
posible. De todos modos existen algunos fallos en el gc bien conocidos 
(referencias cíclicas, módulos con fallos al contar referencias, etc) que 
hace que siempre quede basura sin reciclar. La mejor técnica, según parece, 
que evitaría esta acumulación es la de crear procesos ("forking") 
independientes de modo que una vez acabado el proceso sea el sistema 
operativo el que libere la memoria.


Creo que ya me he alargado mucho. Por completar podría contar lo que pasa con 
las clases, aunque sería largo de contar en profundidad. Por lo general, las 
referencias a métodos y atributos se establecen justo en el momento de la 
evaluación de la expresión y luego se libera la referencia. No hay que 
preocuparse mucho de la memoria que ocupan:

>>> class P:
...   p=0
...   def f():pass
...
>>> a=P()
>>> id(a.p),id(a.f)
(135466584, 1076822380)
>>> del P.p
>>> id(a.p),id(a.f)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: P instance has no attribute 'p'


Hay algunas excepciones que se explican como optimizaciones que hace el python 
al evaluar expresiones:

>>> class P:
...   def f(): pass
...
>>> a=id(P.f)
>>> a==id(P.f)
False
>>> id(P.f)==id(P.f)
True
>>> id(P.f) is id(P.f)
False





- -- 
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-rc1-SuSE (GNU/Linux)

iD8DBQE/chdWHLTQrABk8H0RAoKHAKCxwcv3vjeO5UHjyDLFCpPe4mmX/wCg9Ycp
5n1XPp7+XtuQ7c7hO1g+FV4=
=wtGl
-----END PGP SIGNATURE-----




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