Супер и понимание 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()
и здесь для более подробной информации, почему это делается так.