Как добавить атрибуты модуля в класс с пользовательским поведением - PullRequest
0 голосов
/ 28 декабря 2018

У меня есть модуль в некотором пути.Я хочу создать класс с теми же атрибутами, что и у модуля (чтобы его можно было использовать так же, как у модуля), но выполнить некоторые пользовательские действия перед доступом к атрибутам - например, перезагрузить модуль.

def get_method_with_extra(method_name, module):
    def method_with_extra(self, *args):
        imp.reload(module)
        func_to_call = getattr(module, method_name)
        func_to_call(*args)

    return method_with_extra

class tester():
    def __init__(self, module_path):
        self.module = imp.load_source('module', module_path)
        method_list = [func for func in dir(self.module) if 
callable(getattr(self.module, func))]
        for method_name in method_list:
            method_with_extra = get_method_with_extra(method_name, 
self.module)
            setattr(type(self), method_name, method_with_extra)

Так что, если, например, модуль имеет метод с именем «Parse», я бы хотел, чтобы экземпляр tester - tess - тоже имел его, и чтобы я мог вызывать tess.parse (), который должен перезагрузить внутренниймодуль, а затем вызвать модуль parse ().Вместо этого я получаю эту ошибку:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 4, in __init__
AttributeError: attribute '__call__' of 'namespace#' object is read-only

1 Ответ

0 голосов
/ 28 декабря 2018

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

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

На основена том, что вы сказали в комментарии, я немного изменил ваш код.Я использовал importlib, потому что модуль imp устарел.Также обратите внимание, что «исправление обезьян» (именно так называется эта техника, вы хотите сделать исправление во время выполнения кода) всегда тесно связано с целевым кодом.Если есть изменения, ваш код патча может легко сломаться.

Я написал два файла module.py и test_module.py:

#-----------
# module.py

a = 100
b = 200

# returns something
def sum3(x,y):
    return x + y + 3

# does something
def print_a_b():
    global a
    print(a,b)
    a = a + 1   # test module reloads. If ok, "a" remains 100

#----------------
# test_module.py

import module
import importlib as imp

def get_method_with_extra(method_name, module):
    def method_with_extra(self, *args):
        imp.reload(module) # comment to see that "a" increases
        func_to_call = getattr(module, method_name)
        if args: # function may not have args
            return func_to_call(*args)
        else: # function may not have args
            return func_to_call()

    return method_with_extra

class tester():
    def __init__(self, module_path):
        self.module = imp.import_module('module', module_path)
        method_list = [func for func in dir(self.module)
            if callable(getattr(self.module, func))]
        for method_name in method_list:
            #print(method_name)
            method_with_extra = \
                get_method_with_extra(method_name, self.module)
            setattr(type(self), method_name, method_with_extra)

t = tester('.')
print(t.sum3(1,2))
t.print_a_b()
t.print_a_b() # checking for the reload, "a" should be 100
...