我注意到,许多修改列表内容的列表操作将返回 None,而不是返回列表本身。示例:>>> mylist = ['a', 'b', 'c']>>> empt...
我注意到,许多修改列表内容的列表操作都会返回 None
,而不是返回列表本身。示例:
>>> mylist = ['a', 'b', 'c']
>>> empty = mylist.clear()
>>> restored = mylist.extend(range(3))
>>> backwards = mylist.reverse()
>>> with_four = mylist.append(4)
>>> in_order = mylist.sort()
>>> without_one = mylist.remove(1)
>>> mylist
[0, 2, 4]
>>> [empty, restored, backwards, with_four, in_order, without_one]
[None, None, None, None, None, None]
这个决定背后的想法是怎样的?
在我看来,这似乎是一种阻碍,因为它阻止了列表处理的“链接”(例如 mylist.reverse().append('a string')[:someLimit]
)。我想可能是“当权者”认为列表理解是一种更好的范例(一种有效的观点),因此不想鼓励其他方法 - 但阻止直观的方法似乎是一种不合情理的做法,即使存在更好的替代方案。我很想知道以这种方式设计语言时做出的决定和权衡。
This question is specifically about Python's design decision to return None
from mutating list methods like .append
. However, novices often write incorrect code that expects .append
(in particular) to return the same list that was just modified. Please do close such questions as a duplicate of this one, however. "The code did the wrong thing because the result was None
rather than the list" is something that the OP in these cases should have discovered independently via debugging; creating a proper MRE leaves behind a question like this one - therefore, it can be considered a duplicate.
See 如何将重复计算的结果收集到列表、字典等中(或复制每个元素均经过修改的列表)? for the simple question of " how do I append to a list repeatedly?" (or debugging questions that boil down to that problem). This is a new canonical that has been specifically prepared to address the topic with the perspective that beginners lack.
要获取列表的修改版本,请参阅:
.extend
)
.remove
)
The same issue applies to some methods of other built-in data types, e.g. set.discard
(see 如何使用列表推导从列表内的集合中删除特定元素 ) and dict.update
(see 为什么 python dict.update() 不返回对象? ).
The same reasoning applies to designing your own APIs. See 让就地操作返回对象是不是一个坏主意? .
Python 中的一般设计原则是让 functions that mutate an object in-place to return None
。我不确定这是否是我选择的设计,但它基本上是为了强调不会返回新对象。
在 Python-Dev 邮件列表中 说明了设计选择 :
我想再次解释一下为什么我如此坚持sort()不应该返回“self”。
这源自一种编码风格(在其他各种语言中很流行,我相信 Lisp 尤其喜欢它),其中对单个对象的一系列副作用可以像这样链接起来:
x.compress().chop(y).sort(z)
这与
x.compress() x.chop(y) x.sort(z)
我发现链式调用形式对可读性有威胁;它要求读者必须非常熟悉每种方法。第二种形式清楚地表明,这些调用中的每一个都作用于同一个对象,因此,即使您不太了解该类及其方法,也可以理解,第二个和第三个调用应用于 x(并且所有调用都是为了它们的副作用),而不是其他东西。
我想保留返回新值的操作的链接,比如字符串处理操作:
y = x.rstrip("\n").split(":").lower()
有一些标准库模块鼓励副作用调用的链接(我想到了 pstat)。不应该有任何新的;当 pstat 很弱时,它就从我的过滤器中溜走了。