Python print()方法将传递的表达式与计算输出一起打印,以便快速调试
我希望能够使用print()或类似的方法执行python调试,在这种方法中,除了通常的输出外,还可以打印传递的表达式 例如,对于以下代码:Python print()方法将传递的表达式与计算输出一起打印,以便快速调试,python,debugging,logging,Python,Debugging,Logging,我希望能够使用print()或类似的方法执行python调试,在这种方法中,除了通常的输出外,还可以打印传递的表达式 例如,对于以下代码: print(42 + 42) print(type(list)) print(datetime.now()) 电流输出: 84 <class 'type'> 2019-08-15 22:43:57.805861 我试图覆盖内置打印,但没有成功: import builtins def print(*args, **kwargs): r
print(42 + 42)
print(type(list))
print(datetime.now())
电流输出:
84
<class 'type'>
2019-08-15 22:43:57.805861
我试图覆盖内置打印,但没有成功:
import builtins
def print(*args, **kwargs):
return builtins.print(*args, **kwargs) # passed expression isn't available here as string!
有没有办法做到这一点?谢谢 调用print方法时,传递的参数不是由print方法计算的,而是在作为参数传递到print方法之前计算的
print(42 + 42) => print(84)
print(type(list)) => print(<type 'type'>)
print(datetime.now()) => print(datetime.datetime(2019, 8, 15, 23, 9, 50, 619157))
print(42+42)=>print(84)
打印(类型(列表))=>print()
print(datetime.now())=>print(datetime.datetime(2019,8,15,23,9,50619157))
内部打印方法只是通过调用传递的对象的_str__()方法将给定对象转换为字符串。一般来说,我认为如果您使用
eval
,可能会有更好的方法来执行您尝试执行的操作,但是:
for statement in ["42 + 42", "type(list)", "datetime.now()"]:
print("{} : {}".format(statement, eval(statement))
您可以定义一个
superprint
函数,让它打印,然后计算一个字符串:
from datetime import datetime
def superprint(str):
print(str," : ",eval(str))
a = "42 + 42"
b = "type(list)"
c = "datetime.now()"
superprint(a)
superprint(b)
superprint(c)
输出
42 + 42 : 84
type(list) : <class 'type'>
datetime.now() : 2019-08-15 14:44:43.072780
42+42:84
类型(列表):
datetime.now():2019-08-1514:44:43.072780
如果你能接受用引号将所有你想打印的东西都打上引号,这对你来说是可行的。f-strings将在Python 3.8+中支持类似的东西 从: 一个f字符串,如f'{expr=}'将扩展到表达式的文本,一个等号,然后是计算表达式的表示形式。例如: 通常的f字符串格式说明符允许更多地控制表达式结果的显示方式: =说明符将显示整个表达式,以便显示计算结果:
编辑:对不起,我的答案不太正确,请看@Augusto Men. 在Python中没有什么是不可能的,但是使用
eval
并不总是有效:
import inspect
from datetime import datetime
def my_print(a):
assert(callable(a))
source = inspect.getsource(a).replace("my_print(lambda:", "").strip()[:-1]
print(source + " : " + str(a()))
# pass lambda function to my_print
print("my_print_result:")
my_print(lambda: 42 + 42)
my_print(lambda: type(list))
my_print(lambda: datetime.now())
def eval_print(s):
print(s + " : " + str(eval(s)))
# another way is passing string to eval_print
# but eval has its own special evaluation rules
# which will not work as expected when used in function
print("\neval_print result:")
eval_print("42 + 42")
eval_print("type(list)")
eval_print("datetime.now()")
def test():
local_test_1 = 1
my_print(lambda: local_test_1 + local_test_1)
eval_print("local_test_1 + local_test_1")
print("\ntest in function:")
test()
输出:
my_print_result:
42 + 42 : 84
type(list) : <class 'type'>
datetime.now() : 2019-08-26 07:06:30.550408
eval_print result:
42 + 42 : 84
type(list) : <class 'type'>
datetime.now() : 2019-08-26 07:06:30.551110
test in function:
local_test_1 + local_test_1 : 2
NameError: name 'local_test_1' is not defined
我的打印结果:
42 + 42 : 84
类型(列表):
datetime.now():2019-08-2607:06:30.550408
评估打印结果:
42 + 42 : 84
类型(列表):
datetime.now():2019-08-2607:06:30.551110
功能测试:
本地_测试_1+本地_测试_1:2
名称错误:未定义名称“本地\u测试\u 1”
在函数中使用eval
时,会出现namererror
,因为Python中的eval
有特殊的规则:
结构与功能
无法访问用于解析名称的完整环境。名字
可以在调用方的本地和全局命名空间中解析<强>免费
变量不是在最近的封闭命名空间中解析的,而是在
全局命名空间。
引用自您可以使用
[1]中的:从日期时间导入日期时间
在[2]中:导入pysnooper
在[3]中:@pysnooper.snoop()
…:def输出():
…:打印(42+42)
…:打印(类型(列表))
…:打印(datetime.now())
...:
在[4]中:输出()
源路径:。。。
22:14:08.934915调用2 def输出()
22:14:08.935031第3行打印(42+42)
84
22:14:08.935061第4行打印(类型(列表))
22:14:08.935083第5行打印(datetime.now())
2019-08-25 22:14:08.935100
22:14:08.935109返回5次打印(datetime.now())
返回值:。。没有一个
您可以使用模块从调用者处获取源代码行(code\u context
):
from inspect import getframeinfo, currentframe
def vprint(value):
caller = currentframe().f_back
info = getframeinfo(caller)
label = ''.join(info.code_context).strip()
label = label.replace('vprint(', '')[:-1].strip()
print(label, '=', value)
>>> vprint(12 + 3)
12 + 3 = 15
>>> vprint(type(list))
type(list) = <type 'type'>
>>> vprint(lambda x: x + 1)
lambda x: x + 1 = <function <lambda> at 0x7f93c104b9b0>
注意:用\
断线可以解决这个问题(尽管缩进看起来仍然很奇怪):
只需使用回溯和搜索调用参数
print(42 + 42) => print(84)
print(type(list)) => print(<type 'type'>)
print(datetime.now()) => print(datetime.datetime(2019, 8, 15, 23, 9, 50, 619157))
此解决方案的优点是不必将表达式放在括号中
import re
import traceback
def prnt_expression(expression):
for s in traceback.format_stack():
match = re.search('prnt_expression\((.*)\)', s)
if match:
expression_string = match.group(1)
break
print(f'{expression_string} : {expression}')
可以这样称呼:
prnt_expression(42 + 42)
以基础为基础,重写Python的Bu建TIN()方法。这将有助于执行调试,而不需要对被测代码进行任何更改,只需在任何文件的顶部添加此函数定义,它就会工作
from inspect import getframeinfo, currentframe
import builtins
def print(*args, **kwargs):
info = getframeinfo(currentframe().f_back)
label = ''.join(info.code_context).strip()
label = label.replace('print(', '', 1)[:-1].strip() # (optional)
return builtins.print(label, ':', *args, **kwargs)
print(42 + 42)
print(type(list))
print(datetime.now())
print([i for i in range(5)])
if 1 < 2: print('True')
从检查导入getframeinfo,currentframe
进口内置设备
def打印(*args,**kwargs):
info=getframeinfo(currentframe().f_-back)
label=''.join(info.code\u context.strip())
label=label.replace('print(','',1)[:-1].strip()#(可选)
返回内置项。打印(标签“:”,*args,**kwargs)
打印(42+42)
打印(类型(列表))
打印(datetime.now())
打印([i代表范围(5)])
如果1<2:打印('True')
输出:
42+42:84
类型(列表):
datetime.now():2019-08-28 16:00:10.812306
[i代表范围(5)]:[0,1,2,3,4]
如果1<2:“真”:真
您可能需要检查
日志记录
模块以获取信息:Python按值传递函数参数,并且在调用print
函数之前必须对所有参数进行求值。因此,当您尝试print(type(list))
时,实际求值的是print(type)
(因为type(list)
的计算结果为类型
)。因此,表达式将永远不会作为字符串提供给您。使用日志记录
您可能可以编写自定义代码,以便日志输出行本身?对于vpri,类似如下所示:INFO“logger.INFO(3+3)”6
In [1]: from datetime import datetime
In [2]: import pysnooper
In [3]: @pysnooper.snoop()
...: def output():
...: print(42 + 42)
...: print(type(list))
...: print(datetime.now())
...:
In [4]: output()
Source path:... <ipython-input-3-d5732f8e9c36>
22:14:08.934915 call 2 def output():
22:14:08.935031 line 3 print(42 + 42)
84
22:14:08.935061 line 4 print(type(list))
<class 'type'>
22:14:08.935083 line 5 print(datetime.now())
2019-08-25 22:14:08.935100
22:14:08.935109 return 5 print(datetime.now())
Return value:.. None
from inspect import getframeinfo, currentframe
def vprint(value):
caller = currentframe().f_back
info = getframeinfo(caller)
label = ''.join(info.code_context).strip()
label = label.replace('vprint(', '')[:-1].strip()
print(label, '=', value)
>>> vprint(12 + 3)
12 + 3 = 15
>>> vprint(type(list))
type(list) = <type 'type'>
>>> vprint(lambda x: x + 1)
lambda x: x + 1 = <function <lambda> at 0x7f93c104b9b0>
>>> vprint([''] +
...: ['a', 'b'])
['a', 'b'] = ['', 'a', 'b']
>>> vprint(math.log(
...: 2 * math.pi))
2 * math.pi) = 1.83787706641
>>> vprint(math.log( \
...: 2 * math.pi))
math.log( 2 * math.pi) = 1.83787706641
import re
import traceback
def prnt_expression(expression):
for s in traceback.format_stack():
match = re.search('prnt_expression\((.*)\)', s)
if match:
expression_string = match.group(1)
break
print(f'{expression_string} : {expression}')
prnt_expression(42 + 42)
from inspect import getframeinfo, currentframe
import builtins
def print(*args, **kwargs):
info = getframeinfo(currentframe().f_back)
label = ''.join(info.code_context).strip()
label = label.replace('print(', '', 1)[:-1].strip() # (optional)
return builtins.print(label, ':', *args, **kwargs)
print(42 + 42)
print(type(list))
print(datetime.now())
print([i for i in range(5)])
if 1 < 2: print('True')
42 + 42 : 84
type(list) : <class 'type'>
datetime.now() : 2019-08-28 16:00:10.812306
[i for i in range(5)] : [0, 1, 2, 3, 4]
if 1 < 2: 'True' : True