__getattr__ на модуле

Как реализовать эквивалент __getattr__ в классе, на модуле?

пример

При вызове функции, которая не существует в статически определенных атрибутах модуля, я хочу создать экземпляр класса в этом модуле и вызвать метод на нем с тем же именем, что и при поиске атрибута модуля.

 class A(object): def salutation(self, accusative): print "hello", accusative # note this function is intentionally on the module, and not the class above def __getattr__(mod, name): return getattr(A(), name) if __name__ == "__main__": # i hope here to have my __getattr__ function above invoked, since # salutation does not exist in the current namespace salutation("world") 

Который дает:

 matt@stanley:~/Desktop$ python getattrmod.py Traceback (most recent call last): File "getattrmod.py", line 9, in <module> salutation("world") NameError: name 'salutation' is not defined 

  • Использование Python «рейз из»
  • Проверка наличия NaN в контейнере
  • Оператор Python 3 >> для печати в файл
  • Добавление цвета в новый стиль ipython (v5)
  • Удаление уже напечатано в Python
  • Openshift: OSError Errno 98 не может обновить сервер
  • Оператор Modulo в Python
  • Простая синтаксическая ошибка в Python, если другое понимание
  • 8 Solutions collect form web for “__getattr__ на модуле”

    Здесь есть две основные проблемы:

    1. Методы __xxx__ рассматриваются только на классе
    2. TypeError: can't set attributes of built-in/extension type 'module'

    (1) означает, что любое решение должно также следить за тем, какой модуль просматривается, иначе каждый модуль будет иметь поведение замены экземпляра; и (2) означает, что (1) даже не возможно … по крайней мере, не напрямую.

    К счастью, sys.modules не придирчивы к тому, что там происходит, поэтому оболочка будет работать, но только для доступа к модулю (т. import somemodule; somemodule.salutation('world') ; для доступа к одному модулю вам в значительной степени придется выдернуть методы из класса подстановок и добавить их в globals() eiher с помощью специального метода в классе (мне нравится использовать .export() ) или с общей функцией (например, те, которые уже указаны как ответы). Следует иметь в виду: если оболочка каждый раз создает новый экземпляр, а глобальное решение – нет, вы оказываетесь в тонком поведении. О, и вы не можете использовать оба одновременно, это одно или другое.


    Обновить

    От Гвидо ван Россума :

    На самом деле есть хак, который иногда используется и рекомендуется: модуль может определить класс с требуемой функциональностью, а затем в конце заменить его в sys.modules экземпляром этого класса (или с классом, если вы настаиваете , но это, как правило, менее полезно). Например:

     # module foo.py import sys class Foo: def funct1(self, <args>): <code> def funct2(self, <args>): <code> sys.modules[__name__] = Foo() 

    Это работает, потому что импортное оборудование активно разрешает этот взлом, а его последний шаг вытаскивает из модуля sys.modules фактический модуль после его загрузки. (Это не случайно. Взлом был предложен давно, и мы решили, что нам достаточно понравилось, чтобы поддержать его в импортной технике.)

    Таким образом, установленный способ выполнить то, что вы хотите, – создать в своем модуле один класс, а последний акт модуля заменит sys.modules[__name__] экземпляром вашего класса – и теперь вы можете играть с __getattr__ / __setattr__ / __getattribute__ при необходимости.

    Это взломать, но вы можете обернуть модуль классом:

     class Wrapper(object): def __init__(self, wrapped): self.wrapped = wrapped def __getattr__(self, name): # Perform custom logic here try: return getattr(self.wrapped, name) except AttributeError: return 'default' # Some sensible default sys.modules[__name__] = Wrapper(sys.modules[__name__]) 

    Обычно мы этого не делаем.

    Мы делаем это.

     class A(object): .... # The implicit global instance a= A() def salutation( *arg, **kw ): a.salutation( *arg, **kw ) 

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

    Например, посмотрите на random модуль, который создает неявный глобальный экземпляр, чтобы немного упростить случаи использования, когда вам нужен «простой» генератор случайных чисел.

    Подобно тому, что предложил @ Håvard S, в случае, когда мне нужно было реализовать некоторую магию на модуле (например, __getattr__ ), я бы определил новый класс, который наследует от types.ModuleType и помещает это в sys.modules (возможно, заменяя модуль где был определен мой собственный ModuleType ).

    См. Основной файл __init__.py Werkzeug для довольно надежной реализации этого.

    Это хаки, но …

     import types class A(object): def salutation(self, accusative): print "hello", accusative def farewell(self, greeting, accusative): print greeting, accusative def AddGlobalAttribute(classname, methodname): print "Adding " + classname + "." + methodname + "()" def genericFunction(*args): return globals()[classname]().__getattribute__(methodname)(*args) globals()[methodname] = genericFunction # set up the global namespace x = 0 # X and Y are here to add them implicitly to globals, so y = 0 # globals does not change as we iterate over it. toAdd = [] def isCallableMethod(classname, methodname): someclass = globals()[classname]() something = someclass.__getattribute__(methodname) return callable(something) for x in globals(): print "Looking at", x if isinstance(globals()[x], (types.ClassType, type)): print "Found Class:", x for y in dir(globals()[x]): if y.find("__") == -1: # hack to ignore default methods if isCallableMethod(x,y): if y not in globals(): # don't override existing global names toAdd.append((x,y)) for x in toAdd: AddGlobalAttribute(*x) if __name__ == "__main__": salutation("world") farewell("goodbye", "world") 

    Это работает путем итерации по всем объектам в глобальном пространстве имен. Если элемент является классом, он выполняет итерацию над атрибутами класса. Если атрибут является вызываемым, он добавляет его в глобальное пространство имен как функцию.

    Он игнорирует все атрибуты, которые содержат «__».

    Я бы не использовал это в производственном коде, но он должен вас начать.

    Вот мой собственный скромный вклад – небольшое приукрашивание высоко оцененного ответа @ Håvard S, но немного более явного (так что это может быть приемлемо для @ S.Lott, хотя, вероятно, и не достаточно для OP):

     import sys class A(object): def salutation(self, accusative): print "hello", accusative class Wrapper(object): def __init__(self, wrapped): self.wrapped = wrapped def __getattr__(self, name): try: return getattr(self.wrapped, name) except AttributeError: return getattr(A(), name) _globals = sys.modules[__name__] = Wrapper(sys.modules[__name__]) if __name__ == "__main__": _globals.salutation("world") 

    Создайте свой файл модуля с вашими классами. Импортируйте модуль. Запустите getattr в модуле, который вы только что импортировали. Динамический импорт можно использовать с помощью __import__ и вытащить модуль из sys.modules.

    Вот ваш модуль some_module.py :

     class Foo(object): pass class Bar(object): pass 

    И в другом модуле:

     import some_module Foo = getattr(some_module, 'Foo') 

    Выполняя это динамически:

     import sys __import__('some_module') mod = sys.modules['some_module'] Foo = getattr(mod, 'Foo') 

    В некоторых случаях словарь globals() может быть достаточным, например, вы можете создать экземпляр класса по имени из глобальной области:

     from somemodule import * # imports SomeClass someclass_instance = globals()['SomeClass']() 
    Python - лучший язык программирования в мире.