如何使用 python 中的 __code__ 获取包装函数的 firstlineno?

How to get firstlineno for wraped function with __code__ in python?

我想以静态方式获取 co_firstlineno for 函数,展开的函数可以, 但是如果一个方法被wrapped,我只能得到wrapper函数所在的lineno

md.py

import functools

def run(func):
    @functools.wraps(func)
    def warper(*args, **kwargs):
        res = func()
        return res
    return warper

def func_unwrapper():
    pass

@run
def func_with_wrapper():
    pass

run.py

from importlib import util as module_util
import inspect

def load_moudle_by_path(path):
    foo = module_util.spec_from_file_location('md', path)
    md = module_util.module_from_spec(foo)
    foo.loader.exec_module(md)
    return md

def get_line():
    md = load_moudle_by_path('md.py')
    for name, o in inspect.getmembers(md):
        if inspect.isfunction(o):
            print('[{}]{}'.format(name, o.__code__.co_firstlineno))

get_line()


>>>
[func_unwrapper]10
[func_with_wrapper]4
[run]3

我明白您的期望,但该行为是预期的行为。

func_with_wrapper 确实是 运行 第 4 行的代码,第 13 行的代码(这可能是您希望/期待的)仅基于 func 参数传递(func_with_wrapper 参数)。

经过您自己的研究,发现 .__wrapped__functools 慷慨地添加,没有必要自己添加类似的东西。

您的原始代码将有效,如果您更新:

def get_line():
    md = load_module_by_path('md.py')
    for name, o in inspect.getmembers(md):
        if inspect.isfunction(o):
            try:
                if o.__wrapped__:
                    print('decorated [{}]{}'.format(name, o.__wrapped__.__code__.co_firstlineno))
            except AttributeError:
                print('undecorated [{}]{}'.format(name, o.__code__.co_firstlineno))

输出:

undecorated [func_unwrapper]10
decorated [func_with_wrapper]13
undecorated [run]3