gpt4 book ai didi

Python timeit命令行错误: "SyntaxError: EOL while scanning string literal"

转载 作者:可可西里 更新时间:2023-11-01 09:40:47 28 4
gpt4 key购买 nike

我一直在使用 Python timeit模块很长一段时间,但它只是通过交互式 Python session 或 Unix shell。现在,我尝试在 Windows 命令提示符 (cmd.exe) 中测量一些代码片段,但它显示此错误:

C:\Users\Me>python -m timeit '"-".join(map(str, range(100)))'
Traceback (most recent call last):
File "C:\Python33\lib\runpy.py", line 160, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "C:\Python33\lib\runpy.py", line 73, in _run_code
exec(code, run_globals)
File "C:\Python33\lib\timeit.py", line 334, in <module>
sys.exit(main())
File "C:\Python33\lib\timeit.py", line 298, in main
t = Timer(stmt, setup, timer)
File "C:\Python33\lib\timeit.py", line 131, in __init__
code = compile(src, dummy_src_name, "exec")
File "<timeit-src>", line 6
'-.join(map(str,
^
SyntaxError: EOL while scanning string literal

这相当令人困惑,因为我没有在字符串中插入任何换行符 - 相反,我实际上直接从 timeit 模块文档中粘贴了示例。

在玩这个的时候,我尝试测试没有任何空格的片段,因为错误标记的字符就在它们之前。即使现在没有发生异常,该模块报告的执行时间也与我传递了一个 pass 语句一样,如下所示:

C:\Users\Me>python -m timeit
100000000 loops, best of 3: 0.013 usec per loop

C:\Users\Me>python -m timeit 'map(str,range(100))'
100000000 loops, best of 3: 0.013 usec per loop

C:\Users\Me>python -m timeit 'map(str,range(1000000000000000))'
100000000 loops, best of 3: 0.013 usec per loop

我确信我正确地调用了模块,因为我在 Unix shell 上粘贴了相同的行并且它们按预期工作。

因为我用 Python 2.7 和 3.3 得到了完全相同的结果(另外,该模块是用纯 Python 编写的,并且已经存在很长时间了)我确信这与 Python 无关,但 Windows相反,命令提示符。

那么,为什么会发生这种奇怪的行为,我该如何解决呢?

最佳答案

tl;dr

对传递给 timeit 模块的语句使用双引号。
示例:

C:\Users\Me>python -m timeit "'-'.join(map(str, range(100)))"
10 loops, best of 3: 28.9 usec per loop

详细解释

bashtcsh 等 Unix shell 相比,单引号在 Windows 命令行中的处理方式不同。

这里有一个小的 python 程序来演示这一点:

import sys
print(sys.argv[1:])

运行它(我们称文件为 cmdtest.py),我们观察到以下内容:

C:\Users\Me\Desktop>python cmdtest.py 1 2 3
['1', '2', '3']

C:\Users\Me\Desktop>python cmdtest.py "1 2 3"
['1 2 3']

C:\Users\Me\Desktop>python cmdtest.py '1 2 3'
["'1", '2', "3'"]

因此,单引号按字面意思处理(即不作为特殊字符)。在 SO 中搜索了一下,我找到了 this great description of argument tokenization by cmd :

When invoking a command from a command window, tokenization of the command line arguments is not done by cmd.exe (a.k.a. "the shell"). Most often the tokenization is done by the newly formed processes' C/C++ runtime, but this is not necessarily so -- for example, if the new process was not written in C/C++, or if the new process chooses to ignore argv and process the raw commandline for itself (e.g. with [GetCommandLine()][1]). At the OS level, Windows passes command lines untokenized as a single string to new processes. This is in contrast to most *nix shells, where the shell tokenizes arguments in a consistent, predictable way before passing them to the newly formed process. All this means that you may experience wildly divergent argument tokenization behavior across different programs on Windows, as individual programs often take argument tokenization into their own hands.

If it sounds like anarchy, it kind of is. However, since a large number of Windows programs do utilize the Microsoft C/C++ runtime's argv, it may be generally useful to understand how the MSVCRT tokenizes arguments. Here is an excerpt:

  • Arguments are delimited by white space, which is either a space or a tab.
  • A string surrounded by double quotation marks is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument. Note that the caret (^) is not recognized as an escape character or delimiter.

错误 #2

考虑到上述情况,让我们首先解释第二个奇怪的行为(充当 pass 语句的行为),因为它更简单一些。由于单引号按字面解释,调用时:

C:\Users\Me>python -m timeit 'map(str,range(100))'

确切的字符串文字 'map(str,range(100))'(包含引号)作为语句传递给时间。
所以,Python 会看到

"'map(str,range(100))'"

代替

'map(str,range(100))'

作为一个字符串,它实际上并没有做任何事情,并且给出了非常接近于 pass 语句的测量值。


错误 #1

现在第一个错误:
正如为 python timeit 所记录的那样模块:

A multi-line statement may be given by specifying each line as a separate statement argument;

所以,调用时:

C:\Users\Me>python -m timeit '"-".join(map(str, range(100)))'

Python 看到 ["'-.join(map(str,", "range(100)))'"] 作为语句传递给 timeit,模块将其解释为多行声明:

'"-".join(map(str,
range(100)))'

它的第一行是一个字符串,它以单引号开头,但从不关闭,因此(最终)解释了奇怪的 EOL 错误。


解决方案

对时间语句使用双引号可以解决问题。

我也尝试过 Windows PowerShell,它比 cmd.exe 更高级,并且表现出与 Unix shell 类似的行为,但并没有完全解决所有问题我测试的语句。
例如,这是可行的(注意语句中的空格):

PS C:\Users\Me> python -m timeit 'map(str, range(100))'
1000000 loops, best of 3: 0.688 usec per loop

虽然最初的例子没有:

PS C:\Users\Me\Desktop> python -m timeit '"-".join(map(str, range(100)))'
option -. not recognized
use -h/--help for command line help

(不过,我还不是很满意。我宁愿做的是让 cmdPowerShell 像 Unix shell 一样工作,这样我就可以简单地粘贴和时间代码片段。如果有人知道一种快速而肮脏的方法来完成此操作(如果可能的话),以完成答案,那就太棒了。)

关于Python timeit命令行错误: "SyntaxError: EOL while scanning string literal",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23987208/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com