Recargar dinámicamente una definición de clase en Python

He escrito un bot IRC usando Twisted y ahora he llegado al punto en el que quiero poder recargar dinámicamente la funcionalidad.

En mi progtwig principal, from bots.google import GoogleBot y miré cómo usar reload para recargar módulos , pero todavía no puedo averiguar cómo hacer una reimportación dinámica de clases.

Entonces, dada una clase de Python, ¿cómo recargo dinámicamente la definición de clase?

La recarga no es confiable y tiene muchos casos de esquina donde puede fallar. Es adecuado para recargar scripts simples y autocontenidos. Si desea recargar dinámicamente su código sin reiniciar, considere usar forkloop en su lugar:

http://opensourcehacker.com/2011/11/08/sauna-reload-the-most-awesomely-named-python-package-ever/

Lo descubrí, aquí está el código que uso:

 def reimport_class(self, cls): """ Reload and reimport class "cls". Return the new definition of the class. """ # Get the fully qualified name of the class. from twisted.python import reflect full_path = reflect.qual(cls) # Naively parse the module name and class name. # Can be done much better... match = re.match(r'(.*)\.([^\.]+)', full_path) module_name = match.group(1) class_name = match.group(2) # This is where the good stuff happens. mod = __import__(module_name, fromlist=[class_name]) reload(mod) # The (reloaded definition of the) class itself is returned. return getattr(mod, class_name) 

Mejor aún, subprocese los complementos, luego hipervise el subproceso, cuando los archivos cambien, vuelva a cargar el proceso de los complementos.

Edición: limpiado.

No puede volver a cargar el módulo usando reload(module) cuando usa el formulario from X import Y Tendrías que hacer algo como reload(sys.modules['module']) en ese caso.

Esta podría no ser necesariamente la mejor manera de hacer lo que quiere, ¡pero funciona!

 import bots.google class BotClass(irc.IRCClient): def __init__(self): global plugins plugins = [bots.google.GoogleBot()] def privmsg(self, user, channel, msg): global plugins parts = msg.split(' ') trigger = parts[0] if trigger == '!reload': reload(bots.google) plugins = [bots.google.GoogleBot()] print "Successfully reloaded plugins" 

Puede usar los sys.modules para recargar dinámicamente los módulos según la entrada del usuario.

Digamos que tienes una carpeta con múltiples complementos como:

 module/ cmdtest.py urltitle.py ... 

Puede usar sys.modules de esta forma para cargar / recargar módulos en función de la entrada de usuario:

 import sys if sys.modules['module.' + userinput]: reload(sys.modules['module.' + userinput]) else: ' Module not loaded. Cannot reload ' try: module = __import__("module." + userinput) module = sys.modules["module." + userinput] except: ' error when trying to load %s ' % userinput 

Cuando realiza una from ... import ... , vincula el objeto al espacio de nombres local, por lo que todo lo que necesita es volver a importarlo. Sin embargo, como el módulo ya está cargado, solo volverá a importar la misma versión de la clase, por lo que también deberá volver a cargar el módulo. Así que esto debería hacerlo:

 from bots.google import GoogleBot ... # do stuff ... reload(bots.google) from bots.google import GoogleBot 

Si por alguna razón no sabe el nombre del módulo, puede obtenerlo de GoogleBot. módulo .

 def reload_class(class_obj): module_name = class_obj.__module__ module = sys.modules[module_name] pycfile = module.__file__ modulepath = string.replace(pycfile, ".pyc", ".py") code=open(modulepath, 'rU').read() compile(code, module_name, "exec") module = reload(module) return getattr(module,class_obj.__name__) 

Hay muchas comprobaciones de errores que puede hacer al respecto. Si utiliza variables globales, probablemente tendrá que averiguar qué sucede en ese momento.