__getattr__ и __getattribute__ для атрибутов class/static динамически генерируемых классов

Этот вопрос отвечает на вопрос, как реализовать __getattr__ для атрибутов static/class - используя метакласс. Однако я хотел бы реализовать __getattr__ и __getattribute__ для класса, сгенерированного type(), и, чтобы сделать вещи еще более интересными, класс наследует класс, который имеет собственный метакласс, который должен выполняться правильно.

Код, резюмирующий абзац выше:

class Inherited(metaclass=SomeFancyMetaclass):
    ...

generated_class = type("GeneratedClass", (Inherited,), {})

def __class_getattr__(cls, name):  # __getattr__ for class, not sure how the code shall look exactly like
    return getattr(cls, name)

setattr(generated_class, "__getattr__", __class_getattr__)  # similarly for __getattribute__

Вопрос: возможно ли это, и если да, то как? Может ли кто-нибудь предоставить минимальный рабочий пример?


person karlosss    schedule 11.04.2019    source источник
comment
Вам нужно реализовать __getattr__ и __setattr__ в метаклассе, но тогда вы должны использовать метакласс для создания класса, я считаю   -  person juanpa.arrivillaga    schedule 12.04.2019
comment
Вместо этого вы можете создать сгенерированный класс в одной строке через: type("GeneratedClass", (Inherited,), {'__getattr__': your_getattr_impl}), а your_getattr_impl должна иметь подпись (self, name) (self, а не cls, потому что экземпляр класса будет передан при использовании), если только вы не хотите делать это на уровне метакласса. Также вам действительно не нужен метакласс для динамического создания класса с настраиваемым атрибутом для функций dunder. Чего именно вы пытаетесь достичь?   -  person metatoaster    schedule 12.04.2019
comment
@metatoaster они пытаются реализовать эти методы разделения в метаклассе, чтобы он работал с атрибутами класса.   -  person juanpa.arrivillaga    schedule 12.04.2019
comment
@ juanpa.arrivillaga Я это понимаю, но если нет веских причин для этого, переопределение как метакласса, так и использование конструкции динамического класса почти всегда является излишним. Я хочу предложить OP использовать одну технику, если нет веских причин использовать их обе.   -  person metatoaster    schedule 12.04.2019
comment
Вы просто должны иметь возможность использовать MyCustomMeta(...,...,...) так же, как вы используете type(...,...,...), но они просто должны фактически реализовать MyCustomMeta Я имею в виду, что все это, вероятно, излишне. Зачем останавливаться сейчас...   -  person juanpa.arrivillaga    schedule 12.04.2019


Ответы (1)


Просто сделайте свой метакласс унаследованным от SomeFancyMetaclass, правильно реализуйте там __getattr____getattribute__) и используйте этот метакласс, а не вызов type для создания унаследованного динамического класса.

Хотя вы используете много редко используемых вещей, на этом пути нет никаких специальных механизмов — это должен быть простой Python —

Конечно, вы не сказали, что вы хотите сделать в специальных методах метакласса - там может быть какая-то черная магия, и если вы делаете __getattribute__, вы всегда должны быть особенно осторожны. , и перенаправить все атрибуты, которые вам не нужны, на супер-вызов, иначе ничего не работает.

Кроме того, имейте в виду, что адаптация доступа к атрибутам, возможная с обоими методами, не будет работать для «создания волшебных методов dunder», то есть: ваш класс не будет волшебным образом иметь метод __add__ или __dir__, потому что ваш метакласс __getattribute__ генерирует один - скорее , они фиксируются в специальных слотах средой выполнения Python, а их проверка и вызов обходят обычный поиск атрибутов в Python.

В противном случае:

class Inherited(metaclass=SomeFancyMetaclass):
    ...

class MagicAttrsMeta(Inherited.__class__):
    def __getattr__(self, attr):
          if attr in ("flying", "circus", "brian", "king_arthur"):
               return "coconut"
          raise AttributeError()


generated_class = MagicAttrsMeta("GeneratedClass", (Inherited,), {})
person jsbueno    schedule 12.04.2019