Динамическая перезагрузка определения класса в Python - PullRequest
3 голосов
/ 10 марта 2012

Я написал IRC-бот с использованием Twisted, и теперь я дошел до того, что хочу иметь возможность динамически перезагружать функциональность.

В моей основной программе я выполняю from bots.google import GoogleBot, и яЯ рассмотрел, как использовать reload для перезагрузки модулей , но я до сих пор не могу понять, как выполнить динамический повторный импорт классов.

Итак, учитывая Python class , как мне динамически перезагрузить определение класса?

Ответы [ 7 ]

2 голосов
/ 10 марта 2012

Перезагрузка ненадежна и имеет много угловых случаев, когда она может потерпеть неудачу.Он подходит для перезагрузки простых, автономных скриптов.Если вы хотите динамически перезагружать свой код без перезапуска, попробуйте вместо этого использовать forkloop:

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

1 голос
/ 11 марта 2012

Я понял, вот код, который я использую:

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)
0 голосов
/ 21 июня 2013
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__)

Существует множество проверок ошибок, которые вы можете выполнить, если вы используете глобальные переменные, вам, вероятно, придется выяснить, что произойдет.

0 голосов
/ 10 марта 2012

Вы можете использовать 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
0 голосов
/ 10 марта 2012

Вы не можете перезагрузить модуль с помощью 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"
0 голосов
/ 10 марта 2012

Еще лучше подпроцесс обработки плагинов, затем гипервизор подпроцесса, когда файлы меняются, перезагрузите процесс плагинов.

Редактировать: очищено.

0 голосов
/ 10 марта 2012

Когда вы делаете from ... import ..., он связывает объект с локальным пространством имен, поэтому все, что вам нужно, это повторно импортировать его.Однако, поскольку модуль уже загружен, он просто повторно импортирует ту же версию класса, так что вам также потребуется перезагрузить модуль.Так что это должно сделать это:

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

Если по какой-то причине вы не знаете название модуля, вы можете получить его из GoogleBot. module .

...