我正在尝试使用3参数type
函数创建嵌套的Python类。我想构造一个类似的东西:
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
如何反射/动态创建完全等同于嵌套定义的嵌套类?
我想用它来反射性地生成graphene-sqlalchemy
api。习惯用法是创建一个外部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
类是一个不错的cookie切割器,应该可以从UserModel
类以编程方式构造。然后,这应该对整个架构都是可行的。
答案 0 :(得分:2)
在Python 3.7 type
文档中,它表示:
[第一个参数]是类名称,并成为
__name__
属性。
因此,我认为您的两个示例之间的唯一区别是,第一个示例中的AA.BB.__name__
是AA.BB
,第二个示例中的BB
。如果您希望__name__
相同,则可以执行以下操作:
AA = type('AA', (), {'BB': type('AA.BB', (), {})})
据我所知,这两个示例在功能上都是等效的。
答案 1 :(得分:2)
实际上,您得到的唯一区别是__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
这对您来说可能就足够了,但是请注意,动态创建的类之间存在更多细微的差异。我回答的最后一个元类问题恰好与此有关,但是采用了相反的方法:挑战在于实际上是否能够区分使用两种样式创建的类。
Detect if class was defined declarative or functional - possible?
(警告:其中包含我在此处回答过的“最深的黑魔法” Python代码)