2012-03-10 2 views
3

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

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

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

+1

Вы пытаетесь самостоятельно изменить код? Почему в противном случае динамически загружать модуль? Во всяком случае проблема заключается в том, что после создания экземпляра, даже если модуль класса перезагружен, экземпляр не будет изменен и продолжит выполнение старого кода.Если вы перезагрузите код класса, вы должны создать своего рода конструктор копий в классе и создать клон экземпляра с новой функциональностью. – immortal

ответ

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

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

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

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

+0

Это именно то, чего я хочу достичь, но мне нужно сделать это программно, учитывая только класс. – damd

0

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

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

+0

Это то, что вы обычно не хотите делать с боттером IRC, так как оно будет закрываться и воссоединяться со всеми каналами, что, вероятно, приводит к некоторому времени, когда он реагирует только вяло из-за дросселирования на стороне ircd. – ThiefMaster

+0

@ThiefMaster Исправлено. –

+0

Спасибо, но мне бы очень хотелось выяснить, как это сделать «мой путь». – damd

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" 
0

Вы можете использовать sys.modules динамически перегружать модули на основе пользовательского ввода.

Скажите, что у вас есть папка с несколькими плагинами, такими как:

module/ 
    cmdtest.py 
    urltitle.py 
    ... 

Вы можете использовать sys.modules таким образом, чтобы загружать/перезагружать модули на основе UserInput:

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 
2

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

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

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

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

Смежные вопросы