Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python print()方法将传递的表达式与计算输出一起打印,以便快速调试_Python_Debugging_Logging - Fatal编程技术网

Python print()方法将传递的表达式与计算输出一起打印,以便快速调试

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()或类似的方法执行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):
    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