Python x或y:可接受的习语,还是混淆?

Python x或y:可接受的习语,还是混淆?,python,coding-style,obfuscation,idioms,Python,Coding Style,Obfuscation,Idioms,我必须从一个可能没有的变量中提取值,并记住一些默认值。我首先编写了以下代码: if self.maxTiles is None: maxX, maxY = 2, 2 else: maxX, maxY = self.maxTiles 然后我意识到我可以把它缩短为: maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2) 但后来我意识到这可能是最简洁易懂的: maxX, maxY = self.max

我必须从一个可能没有的变量中提取值,并记住一些默认值。我首先编写了以下代码:

if self.maxTiles is None:
    maxX, maxY = 2, 2
else:
    maxX, maxY = self.maxTiles
然后我意识到我可以把它缩短为:

maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2)
但后来我意识到这可能是最简洁易懂的:

maxX, maxY = self.maxTiles or (2, 2)

后者是可以接受的,还是太老套了?

除了gddc的答案(假设maxTiles是一个元组的问题),我可能会选择第二个选项,但为了清楚起见,我会添加括号:

maxX, maxY = (self.maxTiles) if (self.maxTiles is not None) else (2, 2)

我不喜欢用
替换Python中的三元运算符。我遇到过很多问题,比如
0
值多次被视为“false”,而我只想检查
None
。我认为明确是更好的,即使它更冗长,所以你的第二个例子是最好的:

maxX, maxY = self.maxTiles if self.maxTiles is not None else (2, 2)

如果你现在就这么做的话,我会用更长的形式,因为它更地道,更容易识别。是的,有更多的行,但你几乎不保存任何字符,适合79个字符行的短行=好


另外,如果您需要调整逻辑或添加更多步骤,您可能会恢复到长格式。

我尽可能避免使用
y if x else z
语法。它本质上是一种丑陋、不直观的语法,也是Python设计中的一个较大错误。这是一个无序表达式:x在y之前求值。这是不直观的;它自然地被解读为“如果x,那么y,或者z”。C的语法为我们提供了几十年来建立的、普遍理解的顺序:
x?y:z
。Python把这一点搞错了

也就是说,三元语法无论如何都是提供默认值的错误机制。在
self.maxTiles中,如果self.maxTiles不是其他(2,2)
,请注意冗余:必须指定
self.maxTiles
两次。这是重复的,所以阅读代码需要更多的工作。例如,如果self.maxTiles不是其他文件(2,2),我必须读两遍以确保它没有说,
self.minTiles

self.maxTiles或(0,2)
避免了这些问题;一目了然

一个警告:如果self.maxTiles是
()
0
或其他一些假值,则结果不同。根据你似乎正在做的事情,这可能是可以接受的,但请记住这一点。当为布尔值或整数提供默认值时,这是一个问题,您确实需要
is None
测试。对于那些我更喜欢一个简单的条件表达式,但有时会使用三元表达式

编辑;编写条件版本的更清晰方法是:

if self.maxTiles is None:
    maxX, maxY = 2, 2
else:
    maxX, maxY = self.maxTiles

您的代码是完全可以接受的习惯用法。事实上,我发现它比前两个更具可读性

我唯一要考虑的是在一行中做两件事,提供一个默认值并将它们解包到x,y中。如果你把它们一分为二可能会更清楚

maxTiles = self.maxTiles or (2, 2)
maxX, maxY = maxTiles
这也转移了对g.d.d.c.的批评,尽管这不是一个真正严肃的批评。

特别是

self.maxTiles if self.maxTiles is not None else (2, 2)
我发现一般形式
的“双重否定”如果不是A:B else:C
(无论是作为陈述还是表达)可能会非常混乱/误导;这不是字面上的
,如果不是。。否则
,但移动
不会使“双负”消失

所以,一般来说,如果A:C else:B
,我只需将这些构造重写为
。在这种特殊情况下,如果我选择了三元运算符形式,我会将其编码为

(2, 2) if self.maxTiles is None else self.maxTiles
关于更一般的问题:
a=b或c
是好的,当且仅当您真的想对
b
的任何假值使用
c
时——专门处理
b
是不好的。依我看,
b或c
是更好的表达方式

b if b else c

但这不是一种表达类似表达式的方法,而核心测试是,
b是None
。理论上,如果您“知道”
b
的唯一可能的假值是
None
,那么它们在语义上是等价的,但是对于代码的读者/维护者来说,强烈的“唯一可能的假值”约束并不明显——如果您必须添加注释来解释这一点,
可能声称的任何简洁性优势均无效。。。在可行的情况下,最好是“用代码表达”,而不是让代码模糊不清,需要注释来明确它在做什么和什么时候(真正有用的注释是那些解释什么和什么时候的注释,而不是解释什么和什么时候[[代码本身应该显示它!-])],而是为什么当它不明显时——这一特定的代码功能的花絮有什么用途)。

最可读的版本是第一个版本。打代码高尔夫时没有赢家。@Andrei,第一个版本有一个令人不快的、任意的,两个分支之间的不必要的不对称可以通过将
if
分支的主体放入
maxX,maxY=2,2
来避免。@Alex:说得好!现在我将它改为镜像else分支,考虑到可维护性,它看起来更吸引人。维护代码的人很可能不是作者!我更喜欢这个。这是一种表达默认值的自然方式。+1-让我们将其推广为默认参数的Python习惯用法的状态:
self.var=default\u value,如果参数不是其他参数
。最少的重复,清楚地表明传递“None”意味着“使用默认值”,并且没有对值进行意外的布尔计算的风险,这会混淆聪明的和/或表达式。我们应该停止避免再使用双重否定@Paul,写出你的第一条评论,如果
None
肯定是已知的不可接受的值,那就好了。否则,在
def
之前的
\u sentinel=object()
,通常在同一范围内,用于
def
(使用
arg=\u sentinel
而不是
arg=None
),然后使用