__ getattr __ на модуле

Как может реализовать эквивалент a __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
114
задан Matt Joiner 5 October 2011 в 09:06
поделиться

5 ответов

Обычно мы так не поступаем.

Мы делаем вот что.

class A(object):
....

# The implicit global instance
a= A()

def salutation( *arg, **kw ):
    a.salutation( *arg, **kw )

Почему? Чтобы неявный глобальный экземпляр был виден.

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

19
ответ дан 24 November 2019 в 02:34
поделиться

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

См. Основной файл __ init __. Py в Werkzeug для достаточно надежной реализации этого.

13
ответ дан 24 November 2019 в 02:34
поделиться

Создайте файл модуля с вашими классами. Импортируйте модуль. Запустите 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')
-2
ответ дан 24 November 2019 в 02:34
поделиться

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

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__])
47
ответ дан 24 November 2019 в 02:34
поделиться

Это халтура, но...

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

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

Он игнорирует все атрибуты, содержащие "__".

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

7
ответ дан 24 November 2019 в 02:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: