Pregunta ¿Cómo descargo (recargo) un módulo de Python?


Tengo un servidor Python de larga duración y me gustaría poder actualizar un servicio sin reiniciar el servidor. ¿Cuál es la mejor manera de hacer esto?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()

605
2018-01-13 00:33


origen


Respuestas:


Puede volver a cargar un módulo cuando ya se haya importado utilizando el reload función incorporada en Python 2:

import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

En Python 3, reload fue movido a la imp módulo. En 3.4, imp fue desaprobado a favor de importliby reload fue agregado a este último. Cuando apunte a 3 o más tarde, haga referencia al módulo apropiado cuando llame reload o importarlo

Creo que esto es lo que quieres. Los servidores web como el servidor de desarrollo de Django usan esto para que pueda ver los efectos de los cambios en su código sin reiniciar el proceso del servidor.

Para citar de los documentos:

El código de los módulos de Python se recompila y   el código de nivel de módulo re ejecutado,   definir un nuevo conjunto de objetos que   están obligados a nombres en el módulo   diccionario. La función init de   los módulos de extensión no se llaman   segunda vez. Como con todos los otros objetos   en Python los viejos objetos son solo   reclamado después de sus recuentos de referencia   caer a cero Los nombres en el módulo   el espacio de nombres se actualiza para apuntar a cualquier   objetos nuevos o cambiados Otro   referencias a los objetos viejos (como   nombres externos al módulo) no son   rebote para referirse a los nuevos objetos   y debe actualizarse en cada espacio de nombres   donde ocurren si eso es deseado.

Como notaste en tu pregunta, tendrás que reconstruir Foo objetos si el Foo clase reside en el foo módulo.


553
2018-01-13 00:34



En Python 3.0-3.3 usaría: imp.reload(module)

los BDFL tiene contestada esta pregunta.

Sin embargo, imp fue desaprobado en 3.4, a favor de importlib (Gracias @Stefan!)

yo pensar, por lo tanto, ahora usarías importlib.reload(module), aunque no estoy seguro


231
2017-10-10 13:36



Puede ser especialmente difícil eliminar un módulo si no es puro Python.

Aquí hay información de: ¿Cómo realmente borro un módulo importado?

Puede usar sys.getrefcount () para averiguar el número real de   referencias.

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

Los números mayores que 3 indican que   será difícil deshacerse de la   módulo. El "vacío" de cosecha propia   (que no contiene nada) módulo debe ser   basura recolectada después

>>> del sys.modules["empty"]
>>> del empty

como la tercera referencia es un artefacto   de la función getrefcount ().


75
2018-01-28 14:03



reload(module), pero solo si es completamente independiente. Si alguna otra cosa tiene una referencia al módulo (o cualquier objeto que pertenezca al módulo), entonces obtendrá errores sutiles y curiosos causados ​​por el código anterior que dure más de lo esperado, y cosas como isinstance no funciona en diferentes versiones del mismo código.

Si tiene dependencias unidireccionales, también debe volver a cargar todos los módulos que dependen del módulo recargado para deshacerse de todas las referencias al código anterior. Y luego vuelva a cargar los módulos que dependen de los módulos recargados, recursivamente.

Si tiene dependencias circulares, que es muy común, por ejemplo, cuando se trata de volver a cargar un paquete, debe descargar todos los módulos del grupo de una vez. No puedes hacer esto con reload() porque volverá a importar cada módulo antes de que se hayan actualizado sus dependencias, permitiendo que las referencias antiguas se filtren a nuevos módulos.

La única manera de hacerlo en este caso es piratear sys.modules, que es algo sin apoyo. Tendría que pasar y eliminar cada sys.modules entrada que quería volver a cargar en la próxima importación, y también eliminar entradas cuyos valores son None para hacer frente a un problema de implementación relacionado con el almacenamiento en caché de importaciones relativas fallidas. No es terriblemente agradable, pero siempre que tenga un conjunto de dependencias totalmente autónomo que no deje referencias fuera de su base de código, es factible.

Probablemente sea mejor reiniciar el servidor. :-)


57
2018-01-13 12:53



if 'myModule' in sys.modules:  
    del sys.modules["myModule"]

52
2017-07-07 11:44



Para Python 2 use la función incorporada recargar():

reload(module)

Para el uso de Python 2 y 3.2-3.3 recargar desde el módulo imp:

import imp
imp.reload(module)

Pero imp  es obsoleto desde la versión 3.4 a favor de Importiblib, entonces usa:

import importlib
importlib.reload(module)

o

from importlib import reload
reload(module)

33
2017-08-09 17:28



El siguiente código le permite la compatibilidad de Python 2/3:

try:
    reload
except NameError:
    # Python 3
    from imp import reload

Lo puedes usar como reload() en ambas versiones, lo que simplifica las cosas.


19
2017-11-20 16:01



La respuesta aceptada no maneja el caso Y de importación X. Este código también lo maneja y el caso de importación estándar:

def importOrReload(module_name, *names):
    import sys

    if module_name in sys.modules:
        reload(sys.modules[module_name])
    else:
        __import__(module_name, fromlist=names)

    for name in names:
        globals()[name] = getattr(sys.modules[module_name], name)

# use instead of: from dfly_parser import parseMessages
importOrReload("dfly_parser", "parseMessages")

En el caso de la recarga, reasignamos los nombres de nivel superior a los valores almacenados en el módulo recién recargado, que los actualiza.


13
2017-09-27 23:30



Para aquellos como yo que desean descargar todos los módulos (cuando se ejecuta en el intérprete de Python en Emacs)

   for mod in sys.modules.values():
      reload(mod)

Más información está en Recarga de módulos de Python.


6
2018-05-08 16:50



Enthought Traits tiene un módulo que funciona bastante bien para esto. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

Volverá a cargar cualquier módulo que se haya cambiado y actualizará otros módulos y objetos instanciados que lo estén usando. No funciona la mayor parte del tiempo con __very_private__ métodos, y puede ahogarse con la herencia de clases, pero me ahorra muchísimo tiempo tener que reiniciar la aplicación host al escribir guis PyQt, o cosas que se ejecutan dentro de programas como Maya o Nuke. No funciona tal vez el 20-30% del tiempo, pero sigue siendo increíblemente útil.

El paquete de Enthought no recarga los archivos en el momento en que cambian, tiene que llamarlo explícitamente, pero eso no debería ser tan difícil de implementar si realmente lo necesita


5
2018-01-09 01:06