我在开发类似于Django _get_queryset(klass)方法的问题时遇到了问题。我正在尝试在提供QuerySet或mongoengine文档时提取QuerySet。我尝试了以下逻辑:
from mongoengine.base import BaseDocument
from mongoengine.queryset import QuerySet
def _get_queryset(klass):
if isinstance(klass, QuerySet):
return klass
if isinstance(klass, BaseDocument):
return klass.objects
else:
raise ValueError
对于给定的文档,例如:
class Monkey(mongoengine.Document):
name = mongoengine.StringField(unique=True)
如果我将以下内容传递给python的is_instance()
>>> isinstance(db.Monkey.objects, QuerySet)
True
但(看似)令人惊讶,
>>> isinstance(Monkey, BaseDocument)
False
>>> isinstance(Monkey(), BaseDocument)
True
isinstance()
出现时是否不实例化该类?在Django中,大致相同的调用有效:
>>> isinstance(Monkey, ModelBase)
True
为什么Monkey
在Django中实例化,而不是在上面的mongoengine版本中?
答案 0 :(得分:3)
在python类中是对象。特别是它们是type
:
>>> class MyClass(object): pass
...
>>> isinstance(MyClass, type)
True
此外,由于object
是最基本类型,因此它们也是object
的实例:
>>> isinstance(MyClass, object)
True
所以,您获得的结果是正确的。类的实例与类本身不同。如果要检查类是否是子类,则有issubclass
函数:
>>> issubclass(MyClass, object)
True
在Django isinstance(Monkey, ModelBase)
中工作的事实是因为在django中ModelBase
不是一个类而是一个元类:
# from django source-code
class ModelBase(type):
"""
Metaclass for all models.
"""
这意味着模型类是其元类的实例(在本例中为ModelBase
)。
答案 1 :(得分:1)
在Python中,类本身就是对象。默认情况下,类的类型为type
(即它是type
类的实例),但可以使用元类覆盖该默认值。使用元类将导致该类成为元类的实例(应扩展type
)。
这意味着如果您使用元类Monkey
定义类ModelBase
,那么Python将创建一个名为ModelBase
的{{1}}对象。 Monkey
对象是一个类,因此您可以实例化Monkey
类型的对象。