为什么inspect返回从超类继承的类的不同行?

时间:2018-09-05 20:21:52

标签: python python-3.6 decorator python-decorators inspect

在尝试找出是否a function is called with the @decorator syntax时,我们意识到,inspect在查看从超类继承的修饰类时具有不同的行为。

在Windows 10下使用CPython 3.6.2发现以下行为。

它也在Linux 64位的CPython 3.7.0中复制。

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 :(得分:6)

进一步的实验表明,这是Python行号分配的一个怪癖。特别是,如果我们使用Cmp.defaultProps = { onChange: () => {} } 来查看code with and without a base class的反汇编,则:

dis

我们看到对于import dis import sys dis.dis(sys._getframe().f_code) def dec(): pass @dec class Foo: pass @dec class Bar(Foo): pass ,所涉及的指令的行号为8(对应于Foo行):

@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行。对于基类,父框架位于“加载基类”行上。