在Python中动态重新加载类定义

时间:2012-03-10 09:33:56

标签: python reflection twisted

我已经使用Twisted编写了一个IRC机器人,现在我已经达到了我希望能够动态重新加载功能的程度。

在我的主程序中,我from bots.google import GoogleBot我已经查看了如何使用reload重新加载模块,但我仍然无法弄清楚如何动态重新导入类。

因此,给定Python ,如何动态重新加载类定义?

7 个答案:

答案 0 :(得分:2)

重新加载是不可靠的,并且有许多可能失败的极端情况。它适用于重新加载简单,自包含的脚本。如果要在不重新启动的情况下动态重新加载代码,请考虑使用forkloop:

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

答案 1 :(得分:1)

我明白了,这是我使用的代码:

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)

答案 2 :(得分:0)

执行from ... import ...时,它会将对象绑定到本地名称空间,因此您需要重新导入它。但是,由于模块已经加载,它只会重新导入相同版本的类,因此您还需要重新加载模块。所以这应该这样做:

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

如果由于某种原因您不知道模块名称,可以从GoogleBot获取。模块

答案 3 :(得分:0)

更好的是对插件进行子处理,然后在文件更改时重新加载子进程,重新加载插件进程。

编辑:清理干净。

答案 4 :(得分:0)

使用reload(module)表单时,无法使用from X import Y重新加载模块。在这种情况下,您必须执行reload(sys.modules['module'])之类的操作。

这可能不一定是最好的方式来做你想要的,但是它有效!

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"

答案 5 :(得分:0)

您可以使用sys.modules根据用户输入动态重新加载模块。

假设您有一个包含多个插件的文件夹,例如:

module/
  cmdtest.py
  urltitle.py
  ...

您可以使用sys.modules以这种方式根据用户输入加载/重新加载模块:

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

答案 6 :(得分:0)

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__)

你可以对此做很多错误检查,如果使用全局变量,你可能需要弄清楚会发生什么。