Python中的缩进并不总是必要的?

Python中的缩进并不总是必要的?,python,if-statement,Python,If Statement,我遇到了一段代码(针对问题进行了简化),其结构如下: while True: if x == y: break 到目前为止,我对Python的理解是,解释器在理解循环和条件等内容时高度依赖于制表符/空格,但上面的代码样式运行时没有问题,这表明这并不完全正确 有人能解释其中的细微差别吗?这就是状态词和复合语句之间的区别。例如,在C中,您可以执行以下操作 for(i=0; i<10; i++) printf("something"); 然后,花括号内的整个内容被视为一个语句 Pyt

我遇到了一段代码(针对问题进行了简化),其结构如下:

while True:
    if x == y: break
到目前为止,我对Python的理解是,解释器在理解循环和条件等内容时高度依赖于制表符/空格,但上面的代码样式运行时没有问题,这表明这并不完全正确


有人能解释其中的细微差别吗?

这就是状态词和复合语句之间的区别。例如,在
C
中,您可以执行以下操作

for(i=0; i<10; i++) printf("something");
然后,花括号内的整个内容被视为一个语句

Python也是如此

if x == y: 
    print 'abcd'   # These two statements are treated as 1 block
    break          # of statements 

如果只有一条语句,就不需要定义块

在Python中,如果块只包含一条语句,则始终可以用一行替换所需的块

例如

它们是等价的。对于Python中需要语法的任何其他块也是如此:

  • 如果,else,elif,for,while,def,class

此处不需要缩进,因为您在的中有,
break

在这种情况下,不需要缩进


您只能通过返回或中断来执行此操作,但如果没有缩进,则不能使用,
如果
。但作为一个简短的总结:

任何“复合语句”,如
if
,都可以使用缩进的语句组,或内联的简单语句列表*

那么,这两者有什么区别呢

if x == y:
    break

if x == y: break
真的,没什么,只是第一个通常被认为更具可读性和惯用性。(《官方风格指南》称,第二种形式“通常不鼓励”,但“有时可以将一个小身材的if/for/while放在同一行上。”**

它们具有完全相同的语义、性能等。它们甚至可以编译成完全相同的字节码。有一个很小的语法差异,但它只影响在各种非法构造中嵌入错误消息时所得到的错误消息


那么,你能在那里放一些比
break
更复杂的东西吗

对。请注意,这是一个简单的语句list。这意味着您可以有多个用分号分隔的简单语句:

if x == y: print('Hey!'); x = -x; break
然而,这是令人难以置信的糟糕风格。除非你想在高尔夫比赛中获胜,否则不要这样做

但也有局限性。请注意,它是一个简单的语句列表。这意味着没有复合语句。这是非法的:

if x == y: while True: print('loopy')
您可以看到简单语句的完整列表


*内联语句列表仍然被认为是官方语法中的一个套件。但在松散的讨论中,suite通常只表示缩进块替代,而不是内联替代


**根据我的经验,有经验的开发人员在代码中看到这一点的最常见的地方实际上是PEP 8说永远不要这样做的地方之一:一个有一堆空函数的类可能会在一行上显示它们,比如
def spam(self):pass
。这会使它们很难粘贴到交互式解释器中,这可能就是PEP 8说永远不要这样做的原因。

这不是正确的规则。有很多if-single语句是不能内联的(就像另一个单行块语句),你可以很容易地将多个语句放到一行中,比如
if-foo:print(x),print(y)
。使用
有效的原因是
print(x),print(y)
计算为
元组。因此,在您刚才描述的情况下,
print(x),print(y)
要求python计算一条语句,该语句将返回一个
tuple
。这通常用于诸如
x,y=5,6
之类的语句中。事实上,您可以将代码中的任何常量放在单独的行中,程序流不会受到影响。这是因为每一行都会被计算,如果一个
=
操作符不存在,结果就会被丢弃。这就是为什么有些人经常在评论中使用多行字符串而不是
#
。@ssm:对不起,如果foo:print(x),这是
的拼写错误;print(y)
,这是一个包含两个简单语句的语句列表。这实际上是一个伪并行。特别是因为如果x==y,您可以编写
:打印'abcd';实际上,在Python中,使用分号分隔行仍然被认为是一个复合语句:不,不是。这是一个
stmt\u列表
,它不是一种
复合stmt
。事实上,如果你看一下,那页上的
语句
被定义为
stmt列表
复合stmt
,因此它们是明显不同的东西。我原以为显示实际语法是个坏主意,但现在我看到它贴在这里,我想即使是很多新手也会得到它。明确+1.差异的奇妙分解。谢谢你。由于缺乏读者Python知识/技能的假设,这个答案成为了赢家。
...
if_stmt      ::=  "if" expression ":" suite
                 ("elif" expression ":" suite)*
                 ["else" ":" suite]
...
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
...
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]
...
if x == y:
    break

if x == y: break
if x == y: print('Hey!'); x = -x; break
if x == y: while True: print('loopy')