【问题标题】:Why does inspect return different line for class inheriting from superclass?为什么检查从超类继承的类返回不同的行?
【发布时间】:2019-02-11 01:21:21
【问题描述】:

在尝试判断 a function is called with the @decorator syntax 是否为inspect 时,我们发现在查看从超类继承的装饰类时,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的行为?

【问题讨论】:

  • 可以在这里在 Python 3.6 上重现,考虑到其他一些实验的结果,这让我感到惊讶。
  • 我可以在 Mac、Linux 和 repl.it 上的交互式解释器(stock 和 IPython)中重现 3.6。但是当我将相同的代码放入脚本时,对于 Linux 和 repl.it 上的两个函数,code_context 都是 None
  • 我可以在脚本中进行复制,除非您使用 IPython 之类的工具,否则我不希望它以交互方式工作,因为交互模式不应该保存源代码。
  • lineno 相差 1,as you can see on repl.it,缩小了查看范围。
  • dis反汇编显示加载基类对象的LOAD_NAME的行号提前了,这在没有基类的情况下不会发生。

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


【解决方案1】:

进一步的实验表明,这是 Python 行号分配的一个怪癖。特别是如果我们用discode with and without a base class的反汇编:

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,加载基类的LOAD_NAME 的行号从11 前进到12:

 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 在装饰器运行时位于@ 行上。对于基类,父框架位于 load-the-base-class 行。

【讨论】:

    猜你喜欢
    • 2017-10-21
    • 2018-05-03
    • 2023-03-29
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 2017-01-18
    相关资源
    最近更新 更多