调用is_instance()似乎不实例化类

时间:2013-03-10 12:43:38

标签: python django mongoengine

我在开发类似于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版本中?

2 个答案:

答案 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类型的对象。