缩进在 Python 3 解释器模式下粘贴代码时出错



当我运行以下代码时,函数内部有空行(无空格),在解释器模式下逐行运行代码时,我得到了与 Python 3.6.5 不同的行为,python3 split.py

# File split.py
def find(s, start, predictor):
for i in range(start, len(s)):
if predictor(s[i]):
return i
return -1
def find_all(s, sep=" tn"):
beg_of_nonsep = 0
while beg_of_nonsep < len(s):
beg_of_nonsep = find(s, beg_of_nonsep, lambda ch, sep_chs=sep: ch not in sep_chs)
if beg_of_nonsep == -1:
break
end_of_nonsep = find(s, beg_of_nonsep + 1, lambda ch, sep_chs=sep: ch in sep_chs)
if end_of_nonsep == -1:
end_of_nonsep = len(s)
yield (beg_of_nonsep, end_of_nonsep)
beg_of_nonsep = end_of_nonsep + 1
split = lambda s: [s[beg: end] for (beg, end) in find_all(s)]
print(split(""))
print(split("     tn"))
print(split("     tssssn"))

在解释器模式下逐行运行代码时,python3给了我令人讨厌的错误:

Type "help", "copyright", "credits" or "license" for more information.
>>> def find(s, start, predictor):
...     for i in range(start, len(s)):
...         if predictor(s[i]):
...             return i
...     return -1
...
>>> def find_all(s, sep=" tn"):
...     beg_of_nonsep = 0
...     while beg_of_nonsep < len(s):
...         beg_of_nonsep = find(s, beg_of_nonsep, lambda ch, sep_chs=sep: ch not in sep_chs)
...         if beg_of_nonsep == -1:
...             break
...
>>>         end_of_nonsep = find(s, beg_of_nonsep + 1, lambda ch, sep_chs=sep: ch in sep_chs)
File "<stdin>", line 1
end_of_nonsep = find(s, beg_of_nonsep + 1, lambda ch, sep_chs=sep: ch in sep_chs)
^
IndentationError: unexpected indent
>>>         if end_of_nonsep == -1:
File "<stdin>", line 1
if end_of_nonsep == -1:
^
IndentationError: unexpected indent
>>>             end_of_nonsep = len(s)
File "<stdin>", line 1
end_of_nonsep = len(s)
^
IndentationError: unexpected indent
>>>
>>>         yield (beg_of_nonsep, end_of_nonsep)
File "<stdin>", line 1
yield (beg_of_nonsep, end_of_nonsep)
^
IndentationError: unexpected indent
>>>
>>>         beg_of_nonsep = end_of_nonsep + 1
File "<stdin>", line 1
beg_of_nonsep = end_of_nonsep + 1
^
IndentationError: unexpected indent
>>>
>>> split = lambda s: [s[beg: end] for (beg, end) in find_all(s)]
>>>
>>> print(split(""))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
TypeError: 'NoneType' object is not iterable
>>> print(split("     tn"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
TypeError: 'NoneType' object is not iterable
>>> print(split("     tssssn"))

这里的最后一个print永远不会退出,直到我使用ctrlc停止它。

因此,我认为我的代码有很多错误。

但是,当我使用python3 split.py运行代码时,这一切都没有发生:

[]
[]
['ssss']

这让我相当困惑。

需要明确的是,我实际上是在 Debian 9.8 和 vim 8.1 上使用 vimcmdline。

我还使用pylintpymode,它拆分了任何尾随空格,它认为这是多余的。

当我尝试使用其内置的键绑定将split.py发送到它打开的tmux拆分中的python3时,发生了此问题。

我已经填写了一个问题,但我不禁想知道为什么python3会这样。

这种行为对我来说并不奇怪。

Python 使用缩进来确定代码块的开头和结尾。 逻辑缩进在缩进的第一行结束。 运行脚本时,将忽略空行。 当运行脚本时,这意味着缩进以未缩进行或文件结尾结束。

但是此行为无法在命令行模式下工作,因为文件没有结尾。 请考虑以下脚本文件:

from somewhere import bar, do_something
for foo in bar:
do_something(foo)

在脚本中,文件的末尾指示它现在应该运行 for 循环。 它知道没有更多要执行的了。 但是在命令行模式下,命令行仍然打开,您仍然可以编写更多内容。 它不知道你的下一行代码是在 for 循环内部还是外部。 但是命令行不能只是坐等你的下一行代码......您希望它执行...现在!

因此,命令行的操作有一个特定的区别。 空行也将结束代码块。 所以这很好:

from somewhere import bar, do_something, do_something_else
for foo in bar:
do_something(foo)
do_something_else(foo)

但这是一个错误:

from somewhere import bar, do_something, do_something_else
for foo in bar:
do_something(foo)
do_something_else(foo)

因为您已经用空行结束了 for 循环,并且无法添加到其中。

另一种选择是在行尾添加一个继续字符"\",就在函数定义中的空白行之前(至少对于仅包含函数的代码示例,例如,没有类或其他构造会以空行结尾)。

下面显示了继续字符如何允许粘贴代码:

>>> def find_all(s, sep=" tn"):
...     beg_of_nonsep = 0
...     while beg_of_nonsep < len(s):
...         beg_of_nonsep = find(s, beg_of_nonsep, lambda ch, sep_chs=sep: ch not in sep_chs)
...         if beg_of_nonsep == -1:
...             break                               
... 
...         end_of_nonsep = find(s, beg_of_nonsep + 1, lambda ch, sep_chs=sep: ch in sep_chs)
...         if end_of_nonsep == -1:
...             end_of_nonsep = len(s)              
... 
...         yield (beg_of_nonsep, end_of_nonsep)    
... 
...         beg_of_nonsep = end_of_nonsep + 1
... 
>>> split = lambda s: [s[beg: end] for (beg, end) in find_all(s)]

我并不是说这是一个很好的解决方案,但它确实有效。

最新更新