Вопрос по python, class-method, runtime – Методы динамического класса Python

4

Скажи, что есть:

class A(B):
    ...

гдеB может бытьobject а также... являетсяnot:

@classmethod # or @staticmethod
def c(cls): print 'Hello from c!'

Что я должен сделать это призваниеA.c() не вызываетAttributeError?

Другими словами, я знаю, что можно вручную добавить методы класса в класс во время выполнения. Но возможно ли сделать это автоматически, скажем, каждый раз, когда отсутствует метод класса, он создает какой-то фиктивный метод?

Другими словами, только если бы я мог заменитьA.__dict__ с моим диктом, который обрабатывает__getitem__ - ноA.__dict__ кажется, не для записи ...

Ваш Ответ

3   ответа
1

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

В этом случае все, что нужно сделать, это установить метакласс__getattr__ функция для автоматического создания желаемого атрибута класса.

(Задача setattr, getattr состоит в том, чтобы позволить Python выполнять transoform для функции function & gt; без необходимости с ним связываться)

class AutoClassMethod(type):
    def __getattr__(cls, attr):
        default = classmethod(lambda cls: "Default class method for " + repr(cls))
        setattr(cls, attr, default)
        return getattr(cls, attr)



class A(object):
    __metaclass__ = AutoClassMethod
    @classmethod
    def b(cls):
        print cls
12

Вы можете достичь этого с помощью__getattr__ hook наметаклассом.

class DefaultClassMethods(type):
    def __getattr__(cls, attr):
        def _defaultClassMethod(cls):
            print 'Hi, I am the default class method!'
        setattr(cls, attr, classmethod(_defaultClassMethod))
        return getattr(cls, attr)

Демо-версия:

>>> class DefaultClassMethods(type):
...     def __getattr__(cls, attr):
...         def _defaultClassMethod(cls):
...             print 'Hi, I am the default class method!'
...         setattr(cls, attr, classmethod(_defaultClassMethod))
...         return getattr(cls, attr)
... 
>>> class A(object):
...     __metaclass__ = DefaultClassMethods
... 
>>> A.spam
<bound method DefaultClassMethods._defaultClassMethod of <class '__main__.A'>>
>>> A.spam()
Hi, I am the default class method!

Обратите внимание, что мы устанавливаем результатclassmethod звоните прямо в класс, эффективно кэшируя его для будущих поисков.

Если вам нужно регенерировать метод класса при каждом вызове, используйте тот жеметод для привязки функции к экземпляру но вместо этого с классом и метаклассом (используяcls.__metaclass__ быть совместимым с подклассами метакласса):

from types import MethodType

class DefaultClassMethods(type):
    def __getattr__(cls, attr):
        def _defaultClassMethod(cls):
            print 'Hi, I am the default class method!'
        return _defaultClassMethod.__get__(cls, cls.__metaclass__)

Для статических методов просто возвращайте функцию напрямую во всех случаях, нет необходимости гадать сstaticmethod декоратор или дескриптор протокола.

Отлично! Спасибо! Ecir Hana
A.asd () - AttributeError: "тип объекта" A "; не имеет атрибута "asd" & quot; Ecir Hana
@EcirHana: ах, вы имеете в виду метод класса по умолчанию, будет обновляться.
Я хочу, чтобы спам был методом класса, а не методом экземпляра. Ecir Hana
0
>>> class C(object):
...     pass
... 
>>> C.m = classmethod(lambda cls: cls.__name__)
>>> C.m()
'C'

Или вы можете использовать что-то вроде этого:

class Wrapper(object):

    def __init__(self, clz, default=lambda cls: None):
        self._clz = clz
        self._default = default

    def __getattr__(self, attr):
        # __attrs__ will be getted from Wrapper
        if attr.startswith('__'):
            return self.__getattribute__(attr)

        if not hasattr(self._clz, attr):
            setattr(self._clz, attr, classmethod(self._default))
        return getattr(self._clz, attr)

    def __call__(self, *args, **kwargs):
        return self._clz(*args, **kwargs)

>>> class C(object):
...     pass
...
>>> C = Wrapper(C, default=lambda cls: cls.__name__)
>>> c = C()
>>> print C.m()
'C'
>>> print c.m() # now instance have method "m"
'C'
@EcirHana, я пытался реализовать какую-то оболочку ...
@EcirHana, Python создает объекты класса при импорте модуля. И у этого класса-объекта нет метода__getattribute__ или какой-то эквивалент ...
Спасибо. Да, я знаю, что вы можете добавлять методы класса вручную. Есть ли способ сделать это автоматически? Ecir Hana

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