Дальнейший эксперимент показывает, что это причуды присваивания номера строки Python. В частности, если мы используем dis
, чтобы увидеть разборку кода с базовым классом и без него :
import dis
import sys
dis.dis(sys._getframe().f_code)
def dec(): pass
@dec
class Foo: pass
@dec
class Bar(Foo): pass
Мы видим, что для Foo
соответствующие инструкции имеют строку номер 8 (соответствующую строке @dec
):
8 58 LOAD_NAME 4 (dec)
61 LOAD_BUILD_CLASS
62 LOAD_CONST 4 (<code object Foo at 0x2b2a65422810, file "./prog.py", line 8>)
65 LOAD_CONST 5 ('Foo')
68 MAKE_FUNCTION 0
71 LOAD_CONST 5 ('Foo')
74 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
77 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
80 STORE_NAME 5 (Foo)
Но для Bar
номер строки увеличивается с 11 до 12 для LOAD_NAME
, который загружает базовый класс:
11 83 LOAD_NAME 4 (dec)
86 LOAD_BUILD_CLASS
87 LOAD_CONST 6 (<code object Bar at 0x2b2a654a0f60, file "./prog.py", line 11>)
90 LOAD_CONST 7 ('Bar')
93 MAKE_FUNCTION 0
96 LOAD_CONST 7 ('Bar')
12 99 LOAD_NAME 5 (Foo)
102 CALL_FUNCTION 3 (3 positional, 0 keyword pair)
105 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
108 STORE_NAME 6 (Bar)
Без базового класса, f_lineno
родительского фрейма находится в строке @
при запуске декоратора. В базовом классе родительский фрейм находится в строке загрузки базового класса.