__instancecheck__ - перезапись не дает никакого эффекта - что я делаю не так? - PullRequest
0 голосов
/ 04 сентября 2018

Я пытаюсь сделать мой класс другим объектом, чтобы обойти ленивую проверку типов в пакете, который я использую. Точнее говоря, я пытаюсь сделать так, чтобы мой объект выглядел как экземпляр другого объекта (tuple в моем случае), хотя на самом деле он даже не является производным от этого.

Чтобы достичь этого, я планирую переписать метод __isinstance__, который, согласно документам , должен делать именно то, что я хочу. Однако, похоже, что я не понимал, как это сделать, потому что мои попытки не увенчались успехом.

Вот SSCCE, который должен заставить isinstance вернуть False во всех случаях, но не делает.

class FalseInstance(type):
    def __instancecheck__(self, instance):
        return False

class Foo(metaclass=FalseInstance):
    pass

g = Foo()
isinstance(g, Foo)
> True

Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 04 сентября 2018

Помимо проблем с __metaclass__ и быстрого пути для точного соответствия типов, __instancecheck__ работает в направлении, противоположном тому, что вы пытаетесь сделать. Класс __instancecheck__ проверяет, считаются ли другие объекты виртуальными экземплярами этого класса, а не считаются ли экземпляры этого класса виртуальными экземплярами других классов.

Если вы хотите, чтобы ваши объекты лгали о своем типе в isinstance проверках (вы действительно не должны), то способ сделать это состоит в том, чтобы лгать о __class__, а не реализовывать __instancecheck__.

class BadIdea(object):
    @property
    def __class__(self):
        return tuple

print(isinstance(BadIdea(), tuple)) # prints True

Кстати, если вы хотите получить фактический тип объекта, используйте type вместо проверки __class__ или isinstance.

0 голосов
/ 04 сентября 2018

Если вы добавите отпечаток внутри FalseInstance.__instancecheck__, вы увидите, что он даже не вызывается. Однако, если вы позвоните isinstance('str', Foo), то увидите, что FalseInstance.__instancecheck__ действительно вызывается.

Это связано с оптимизацией в реализации isinstance, которая немедленно возвращает True, если type(obj) == given_class:

int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
    _Py_IDENTIFIER(__instancecheck__);
    PyObject *checker;

    /* Quick test for an exact match */
    if (Py_TYPE(inst) == (PyTypeObject *)cls)
        return 1;
    .
    .
    .
}

Из исходного кода Python

...