为什么在此python代码段中允许使用分号?


166

Python不保证使用分号来结束语句。那么为什么允许这个(如下)?

import pdb; pdb.set_trace()

1
请注意,此类代码仅用于调试目的,并且可能在“完成”之前被删除。我会像使用它一样使用该代码段,因此我可以轻松地移动它。
尼克T

大声笑我从同一个网站来到这个问题:realpython.com/python-debugging-pdb
mackycheese21 '19

Answers:


225

Python并不需要分号来终止语句。如果您希望将多个语句放在同一行上,可以使用半冒号来分隔语句。

现在,为什么允许这样做?这是一个简单的设计决定。我认为Python不需要这种分号的东西,但是有人认为将其添加到语言中会很好。


16
它对类似的东西很有用timeit a = 5; a*a
endolith 2013年

13
对于exec语句来说似乎很有用,例如exec('for in [1,2,3]:print a; print a + 1')
Phil C

75
我以C,Obj-C,Javascript和PHP为背景来到Python。我经常放一个(没用的)终结符;在一行的末尾。但是幸运的是Python原谅了我
Paolo

36
分号在django shell或调试器中非常有用,因此您可以在一行上编写一个小程序,以后再重复。
布莱斯

5
@endolith是什么timeit意思?a = 2; a*a是无用的,因为a仍然是2;它必须是a = 2; a *= a
Nearoo

58

http://docs.python.org/reference/compound_stmts.html

复合语句由一个或多个“子句”组成。子句由标题和“套件”组成。特定复合语句的子句标题都位于相同的缩进级别。每个子句头均以唯一标识的关键字开头,并以冒号结尾。套件是由子句控制的一组语句。套件可以是在标头的冒号之后,与标头在同一行上的一个或多个用分号分隔的简单语句,也可以是在后续行上的一个或多个缩进语句。只有后者的套件形式可以包含嵌套的复合语句;以下是非法的,主要是因为不清楚else子句属于哪个if子句:

if test1: if test2: print x

还要注意,在这种情况下,分号比冒号绑定更紧密,因此在以下示例中,将执行全部或不执行任何打印语句:

if x < y < z: print x; print y; print z 

总结:

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | funcdef
                   | classdef
                   | decorated
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

4
不知道if后分号优先于冒号的优先级。谢谢!
2014年

3
@gaborous我个人觉得您的评论含糊不清,以至于我以为您是相反的意思。因此,为澄清起见,我宁愿建议其他读者继续使用官方用语:在该if cond: stmt1; stmt2; stmt3示例中,全部或全部语句都不执行。”
RayLuo

是的,这就是我的意思,如果优先级较低,则词法分析器无法在执行所有分号语句之前离开父(冒号)块。这确实不是显而易见的事情。
令人赞叹的

38

Python将;用作分隔符,而不是终止符。您还可以在行的末尾使用它们,这使它们看起来像语句终止符,但这是合法的,因为空白语句在Python中是合法的-末尾包含分号的行是两个语句,第二个一个空白。


28
如果将双分号放在末尾(或任何地方),则会出现SyntaxError。因此,似乎空白声明并不完全合法。
Cucu

10
它的逻辑与列表,元组,带尾部逗号的字典相同,且与它们的修剪对等字符相同(例如[1,2,3] == [1,2,3,]),但它们不能包含双逗号。因此,基本上,Python有一个“尾随空白删除器”。顺便说一下,这很清楚:stmt_list ::= simple_stmt (";" simple_stmt)* [";"]
Cucu 2013年

@Cucu你是对的。您也不能以分号开头的行,也不能以逗号开头的表达式列表。因此,准确地说分号和逗号是分隔符可选的终止符。
wjandrea

28

口译中的分号

阅读答案后,我仍然想念使用分号的一个重要方面,可能是唯一真正起作用的方面。

当您在解释器REPL(Python交互式外壳,IDLE,ipython)中工作时,最后一个表达式的值会显示在屏幕上,通常这是预期的行为。

使用表达式产生副作用

但是在某些情况下,您只想评估一个表达式的副作用,例如,查看仿真结果,由 matplotlib

在这种情况下,你(可能)不希望看到的屏面reprmatplotlib对象有时会通过调用返回到matplotlib至少一种功能,在IPython中,你有一种可能性是分号追加到过度冗长的语句,现在IPython看到输入行是由两个表达式(matplotlib调用和null语句)组成的,因此复合表达式的值为,None解释器不会在屏幕上显示任何内容(另一种可能是assign,如_ = plot(...)但我发现这更具侵入性)。

个人评论

恕我直言,在IPyton笔记本电脑问世之后,使用分号在解释器中抑制不想要的输出变得更加相关,该笔记本可以保存解释器会话的输入和输出(包括图形输出),以供文档记录和最终重用。


我明白了,谢谢分享!这恰好解决了我的问题,其中分号可以通过ipython笔记本中的matplotlib阻止repr
Napitupulu Jon

这是仅IPython的功能,它不是null语句,只是一种特殊的语法。
wjandrea

@wjandrea你是正确的,只是ipython...我已编辑我的回答以反映你的评论。
gboffi

12

正如其他所有人都指出的那样,您可以使用分号来分隔语句。你不必到,这不是一贯的作风。

至于为什么有用,有些人喜欢在一行上放置两个或多个真正的琐碎的简短声明(我个人认为这会将几条琐碎的,容易浏览的行变成一条看起来很复杂的行,使人很难看清它是琐碎的) 。

但是,当您使用调用Shell中的一个衬板时,这几乎是必需的python -c '<some python code>'。在这里,您不能使用缩进来分隔语句,因此,如果单行代码实际上是两行代码,则需要使用分号。而且,如果您想在单行代码中使用其他参数,则必须导入sys才能到达at sys.argv,这需要单独的import语句。例如

python -c "import sys; print ' '.join(sorted(sys.argv[1:]))" 5 2 3 1 4
1 2 3 4 5

2
可以通过命令时,通过使用缩进和换行符python的外壳:只要你跨越引述码多行或使用定界符。但是,如果您希望它成为“单线”,那将失败。;)
00dani 2014年

包含具有以下特征的答案的答案-c
n611x007

6

我意识到我作为一个老C程序员有偏见,但是有时候各种Python约定使事情变得难以理解。我发现缩进约定有时会有些烦人。

有时,清楚声明或块结束的时间非常有用。标准C代码通常会读取如下内容:

for(i=0; i<100; i++) {
    do something here;
    do another thing here;
}

continue doing things;

在哪里使用空格可以使内容更加清晰-而且很容易看到循环的结束位置。

Python确实允许您以(可选)分号终止。如上所述,这并不意味着存在要执行的语句,后跟“空”语句。例如

print(x);
print(y);

是相同的

print(x)
print(y)

如果您认为第一个语句在每一行的末尾都有一个null语句,请尝试-按照建议的方式执行以下操作:

print(x);;

它将引发语法错误。

就个人而言,当您具有大量嵌套和带有许多参数和/或长名称的args的函数时,我发现分号可使代码更易读。因此,在我看来,这比其他选择要清楚得多:

if some_boolean_is_true:
    call_function(
        long_named_arg_1,
        long_named_arg_2,
        long_named_arg_3,
        long_named_arg_4
    );

因为对我来说,它使您知道最后的')'结束了跨越许多行的某些'block'。

我个人认为,PEP样式指南,执行它们的IDE太多了,并且相信“只有一种Python方式可以做事”。如果您相信后者,请看看如何设置数字格式:到目前为止,Python支持四个不同的。

我敢肯定我会被一些顽固分子激怒,但是编译器/解释器不在乎参数是长名称还是短名称,而且-对于Python中的缩进约定-不在乎空格。代码的最大问题是让另一个人(甚至是几个月的工作后的自己)更加清楚地了解正在发生的事情,事情的开始和结束等。



5

引用“ Python攻击时

不要用分号终止所有语句。在Python中执行此操作在技术上是合法的,但是除非您在一行上放置多个语句(例如,x = 1; y = 2; z = 3),否则这是完全没有用的。


4
为什么不x,y,z = 1,2,3呢?
Anirban Nag'tintinmj'2014-2-17

5
@ AnirbanNag'tintinmj'在这种特殊情况下,我认为x, y, z = 1, 2, 3它的运行速度较慢,因为它会导致不必要的来回构建元组,然后立即使它变得相似。(顺便说一句,我并不是真的认为@communistpancake暗示了这种x=1; y=2; z=3模式。我认为他/她只是在举例说明分号是分隔符而不是终止符。)
RayLuo

1
@AnirbanNag-因为那将是多语句行的垃圾示例。
–cz


2

如果您在一行中包含多个语句,Python确实允许您使用分号来表示语句的结尾。



2

分号(如点,逗号和括号)往往会引起宗教战争。尽管如此,由于各种原因,它们(或一些类似的符号)在任何编程语言中还是有用的。

  • 实用:将几条概念上属于同一条的简短命令放在同一行上的能力。看起来像一条狭窄的蛇的程序文本与换行符和缩进所预期的相反,后者突出显示了结构。

  • 概念上的:在过去称为“漂亮打印”的情况下,纯语法(在这种情况下为命令序列)与表示(例如换行符)之间的关注点分离。

观察:对于突出显示的结构,可以用明显的方式用垂直线增加/替换压痕,用作“视觉标尺”以查看压痕的起点和终点。不同的颜色(例如,遵循电阻器的颜色代码)可以补偿拥挤。


1

之所以允许,是因为作者决定允许它:https : //docs.python.org/2/reference/simple_stmts.html

如果质疑作者为什么要这样做,我想是这样,因为至少在以下语言中,允许将半列作为简单的语句终止:C ++,C,C#,R,Matlab,Perl等。

因此,对于有其他语言背景的人们来说,使用Python更快。在这种选择上,也不会失去一般性。


1

仅在同一块中的语句分离时才需要分号(“;”),例如,如果我们具有以下C代码:

if(a>b)
{
largest=a;  //here largest and count are integer variables
count+=1;
}

可以使用以下两种形式之一用Python编写:

if a>b:   
    largest=a
    count=count+1

要么

if a>b:    largest=a;count=count+1

在上面的示例中,一个if块中可以有任意数量的语句,并且可以用“;”分隔。代替。

希望没有像上面的解释那样简单。


0

补充这里提供的大量知识,
这是与matplotlib库相关的答案

import numpy as np
import matplotlib as plt
%matplotlib notebook
linear_data = np.array([1, 2, 3, 4, 5, 6, 7, 8])
quadratic_data = linear_data**2
plt.figure()
xvals = range(len(linear_data))
plt.barh(xvals, linear_data, height = 0.3, color='b')
plt.barh(xvals, quadratic_data, height = 0.3, left=linear_data, color='r')

如果您在barh(水平条)的末尾不提供分号,则输出为图+函数地址。但是,如果在两条barh行的末尾都使用分号,则它仅显示图并抑制函数地址的输出。

像这样: 比较


3
这特定于IPython,不适用于标准的Python REPL。
wjandrea

我认为这是一个出色的例子,语言作者以为他们引入了简单,强大和统一的方式未能像此类问题那样提前思考。
eSurfsnake
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.