создание вложенных классов в Python рефлексивно - PullRequest
0 голосов
/ 27 ноября 2018

Я пытаюсь создать вложенные классы Python, используя функцию type с тремя аргументами.Я хочу построить аналог этого:

In [15]: class CC: 
    ...:     class DD: 
    ...:         pass 
    ...:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

Наивная попытка

In [17]: AA = type('AA', (), {'BB': type('BB', (), {})})                                                                                                                                                                                                                                                                                                                                                                                                                                       

, но это не совсем верно, поскольку BB фактически создается снаружи и до AA и только помещается внутрь `AA позже.

Различие демонстрируется следующим образом:

In [18]: AA.BB                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
Out[18]: __main__.BB

In [16]: CC.DD                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
Out[16]: __main__.CC.DD

Как я могу создавать вложенные классы отражательно / динамически, которые полностью эквивалентны вложенным определениям?


Я хочу использовать это для рефлексивного генерирования API graphene-sqlalchemy.Существует идиома создания внешнего класса Graphene с внутренним Meta-классом, указывающим на соответствующий класс модели SQLAchemy (http://docs.graphene -python.org / projects / sqlalchemy / en / latest / tutorial / # schema )Например:

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import relationship

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class UserModel(Base):
    __tablename__ = 'department'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    last_name = Column(String)

from graphene_sqlalchemy import SQLAlchemyObjectType

class User(SQLAlchemyObjectType):
    class Meta:
        model = UserModel
        # only return specified fields
        only_fields = ("name",)
        # exclude specified fields
        exclude_fields = ("last_name",)

Класс User, приведенный выше, довольно приятен для печенья и должен быть программно из класса UserModel.Это должно быть выполнимо для всей схемы.

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

На самом деле единственное отличие, которое вы получаете, это атрибут класса __qualname__.__qualname__ создается объектом кода, на котором выполняется тело класса, и передается как обычный атрибут метаклассу __new__ методу (обычно type).

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

In [9]: AA = type('AA', (), {'BB': type('BB', (), {'__qualname__': 'AA.BB'})})  

In [10]: AA
Out[10]: __main__.AA

In [11]: AA.BB
Out[11]: __main__.AA.BB

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

Определить, был ли класс определен как декларативный илифункционально - возможно?

(предупреждение: в нем содержится то, что, скорее всего, является кодом Python "самой глубокой черной магии", который я когда-либо помещал в ответ здесь)

0 голосов
/ 27 ноября 2018

В документации Python 3.7 type написано:

[1-й аргумент] является именем класса и становится атрибутом __name__.

Итак, я думаю, единственное различие между вашими двумя примерами состоит в том, что AA.BB.__name__ - это AA.BB в первом примере и BB во втором.Если вы хотите, чтобы __name__ был одинаковым, вы можете сделать это:

AA = type('AA', (), {'BB': type('AA.BB', (), {})})

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

...