简体   繁体   中英

Calling is_instance() does not appear to instantiate class

I'm having an issue with developing something similar to the Django _get_queryset(klass) method. I'm trying to pull a QuerySet when provided with either a QuerySet, or a mongoengine Document. I've tried the following logic:

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

For a given Document, such as:

class Monkey(mongoengine.Document):
    name = mongoengine.StringField(unique=True)

If I pass the following in to python's is_instance()

>>> isinstance(db.Monkey.objects, QuerySet)
True

But (seemingly) surprisingly,

>>> isinstance(Monkey, BaseDocument)
False

>>> isinstance(Monkey(), BaseDocument)
True

Does isinstance() not instantiate the class when presented with it? In Django, a roughly equivalent call works:

>>> isinstance(Monkey, ModelBase)
True

Why does Monkey get instantiated here in Django, but not in the above mongoengine version?

In python classes are objects. In particular they are instances of type :

>>> class MyClass(object): pass
... 
>>> isinstance(MyClass, type)
True

Also, since object is the most base-type they are also instances of object :

>>> isinstance(MyClass, object)
True

so, the result you are obtaining is correct. An instance of a class is something different from the class itself. If you want to check whether a class is a subclass, there is the issubclass function:

>>> issubclass(MyClass, object)
True

The fact that in Django isinstance(Monkey, ModelBase) works is because in django ModelBase is not a class but a metaclass:

# from django source-code
class ModelBase(type):
    """
    Metaclass for all models.
    """

Which means that model classes are instances of their metaclass(in this case ModelBase ).

In Python, classes themselves are objects. By default, a class is of type type (ie it is an instance of the type class), but that default can be overridden by using a metaclass . Using a metaclass will cause the class to be an instance of the metaclass (which should extend type ).

This means that if you define a class Monkey with metaclass ModelBase , then Python will create a ModelBase object named Monkey . The Monkey object is a class, so you can instantiate objects of type Monkey .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM