如何在Python中使用__code__为包装函数获取firstlineno?

问题描述

我想以静态方式获取函数的co_firstlineno,展开函数可以, 但是如果包装了一个方法,我只能得到包装函数所在的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

enter image description here

解决方法

我明白了您的期望,但是这种行为是预期的行为。

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