Супер и понимание Python3 - > TypeError?

использование супер python3 в понимании, кажется, всегда приводит к TypeError: super(type, obj): obj must be an instance or subtype of type (но использование Python 2 super работает так, как ожидалось)

class A(object):
    def __repr__(self):
         return "hi!"  

class B(A):
    def __repr__(self):
         return "".join(super().__repr__() for i in range(2))  

repr(B())
#output: <repr(<__main__.B at 0x7f70cf36fcc0>) failed: TypeError: super(type, obj): obj must be an instance or subtype of type>

class C(A):
    def __repr__(self):
        s = ''
        for i in range(4):
            s += super().__repr__()
        return s     

repr(C())
#output: hi!hi!hi!hi!

class D(A):
    def __repr__(self):
        return "".join(super(D,self).__repr__() for i in range(4))

repr(D())
#output: hi!hi!hi!hi!

Итак, почему new super() сбой в понимании генератора?

дополнение:

In [28]: class E(A):
   ....:     def __repr__(self):
   ....:         def inner():
   ....:             print(repr(__class__))
   ....:         inner()
   ....:         return ''
In [29]: repr(E())
<class '__main__.E'>
Out[29]: ''

In [30]: class F(A):
   ....:     def __repr__(self):
   ....:         return "".join([super().__repr__() for i in range(4)])
   ....:     

In [31]: repr(F())

TypeError: super(type, obj): obj must be an instance or subtype of type

1 ответов


простое объяснение

посмотрите документацию для super():

форма нулевого аргумента работает только внутри определения класса, поскольку компилятор заполняет необходимые сведения для правильного извлечения определяемого класса, а также доступа к текущему экземпляру для обычных методов.

By внутри определения класса они имели в виду внутри метода класса объем. Внутри область метода класса интерпретатор может заполнить нулевую форму с теми же параметрами, что и в Python 2. Однако понимание списка создает свою собственную область. Вот почему он терпит неудачу: вы призываете super() не из области метода класса, и интерпретатор не может завершить его со всеми параметрами.

дополнительные объяснения

согласно Python модель данных:

__class__ является неявной ссылкой закрытия, созданной компилятором, если какие-либо методы в теле класса ссылаются на __class__ или super. Это позволяет нулевой форме аргумента super() чтобы правильно определить класс, определяемый на основе лексической области, в то время как класс или экземпляр, который использовался для выполнения текущего вызова, идентифицируется на основе первого аргумента, переданного методу.

Python может собирать первый параметр для super() С __class__ переменной даже внутри понимание списка (поскольку оно доступно во всех дочерних областях как любое обычное закрытие). Вы можете проверить его с помощью:

class T:
    def test(self):
        print(__class__)
        print([__class__ for _ in range(1)][0])


T().test()

вывод:

<class '__main__.T'>
<class '__main__.T'>

но интерпретатор неправильно собирает второй параметр для super(): self. Он предполагает, что вызов super() происходит внутри области метода и пытается получить первый параметр для метода, используя следующий C код (многие строки опущены для ясности):

PyFrameObject *f = PyThreadState_GET()->frame;
obj = f->f_localsplus[0];
if (obj != NULL) {
    obj_type = supercheck(type, obj);
    if (obj_type == NULL)
        return -1;
    Py_INCREF(obj);
}

невозможно доступ f->f_localsplus[0] из Python, но это содержит "locals+stack" в соответствии с комментарием в коде. Таким образом, мы можем использовать locals() для теста (к сожалению, приказ отсутствует). Давайте проверим, что доступно в locals внутри метода класса и понимания списка:

class T:
    def test(self):
        print(locals())
        print([locals() for _ in range(1)])


T().test()

выведет:

{'self': <__main__.T object at 0x100f1f8d0>}
{'_': 0, '.0': <range_iterator object at 0x100fbb2a0>}

в первом случае есть ссылка на наш объект, и она будет правильно найдена интерпретатором. Внутри понимания списка нет объекта внутри словаря так что он получит либо 0 или range_iterator (помните, порядок отсутствует?). Ни то, ни другое не является примером нашего объекта. Это не удастся supercheck() и дать вам ошибки obj must be an instance or subtype of type (например,T).


посмотреть здесь для получения дополнительной информации о том, как super() и здесь для более подробной информации, почему это делается так.