有没有办法以字符串形式获取上下文管理器中的源代码?

问题描述 投票:0回答:3

函数的源代码可以通过inspect.getsourcelines(func)

函数接收。有没有办法为上下文管理器做同样的事情?

with test(): print('123') # How to get "print('123')" as line here?
    
python
3个回答
3
投票
您对这个解决方案有何看法?

import traceback class ContextManagerContent(object): def __enter__(self): return def __exit__(self, _type, value, _traceback): stack = traceback.extract_stack() f, last_line = self._get_origin_info(stack) with open(f) as fin: lines = list(fin) search = 'with {cls_name}'.format(cls_name=self.__class__.__name__) for i, x in enumerate(lines[:last_line + 1][::-1]): if search in x: first_line = len(lines) - i break selected_lines = lines[first_line:last_line + 1] print ''.join(selected_lines) def _get_origin_info(self, stack): origin = None for i, x in enumerate(stack[::-1]): if x[2] == '__exit__': origin = stack[::-1][i + 1] break return origin[0], origin[1] - 1 with ContextManagerContent(): print '123' print '456' print '789'

如果将其保存在

.py

 文件中并运行它,您可以看到打印数字 123、456 和 789,之后您可以看到上下文管理器的块。

请注意,我没有处理可能的异常或输出格式,并且某些部分可以改进,但我认为这是一个很好的起点。


1
投票
这是另一个受@se7entyse7en 答案启发的解决方案。我认为这样更干净、更高效

from inspect import currentframe, getframeinfo from contextlib import contextmanager @contextmanager def debug(string): # before block cf = currentframe() first_line = cf.f_back.f_back.f_lineno filename = getframeinfo(cf.f_back.f_back).filename yield # after block cf = currentframe() last_line = cf.f_back.f_back.f_lineno with open(filename) as f: lines = f.readlines()[first_line:last_line] print(string + '\n' + ''.join(lines).rstrip()) if __name__ == '__main__': with debug("show this code in stdout:"): a = 1 b = 2 a, b = b, a
    

0
投票
现有的解决方案都不适合我,所以这是另一个实现。

import inspect, linecache from pathlib import Path import tempfile class ContextCodeCapture(): def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): cf = inspect.currentframe().f_back filename = cf.f_code.co_filename line = cf.f_lineno lines = [] indent = 0 i = 1 while True: next_line = linecache.getline(filename, line + i) next_line_indent = len(next_line) - len(next_line.lstrip()) if indent == 0: indent = next_line_indent elif (next_line_indent < indent and len(next_line.strip()) > 0) or next_line == "": break if next_line == "\n": # preserve newlines lines.append(next_line) else: lines.append(next_line[indent:]) i += 1 content = "".join(lines) print(content) if __name__ == "__main__": with ContextCodeCapture(): def say_hello(name): print(f"Hello {name}") foo = 2 if True: for i in range(100): foo *= i
运行此示例将打印以下输出

def say_hello(name): print(f"Hello {name}") foo = 2 if True: for i in range(100): foo *= i
    
© www.soinside.com 2019 - 2024. All rights reserved.