Почему inspect возвращает другую строку для наследования класса от суперкласса? - PullRequest
0 голосов
/ 05 сентября 2018

Пытаясь выяснить, вызывается ли функция с синтаксисом @decorator , мы поняли, что inspect ведет себя по-разному, глядя на декорированный класс, который наследуется от суперкласса.

Следующее поведение было обнаружено с CPython 3.6.2 под Windows 10.

Он также был воспроизведен в CPython 3.7.0 под 64-битной версией Linux.

import inspect

def decorate(f):
    lines = inspect.stack()[1].code_context
    print(f.__name__, lines)

    return f

@decorate
class Foo:
    pass

@decorate
class Bar(dict):
    pass

Выход

Foo ['@decorate\n']
Bar ['class Bar(dict):\n']

Почему наследование меняет поведение inspect?

1 Ответ

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

Дальнейший эксперимент показывает, что это причуды присваивания номера строки 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 родительского фрейма находится в строке @ при запуске декоратора. В базовом классе родительский фрейм находится в строке загрузки базового класса.

...