错误发生
下面的代码对 list 对象使用了 append()方法添加一个元素,并将其存入一个元组,以供后续操作。但在代码后续运行的时候发生了错误,报错信息是正在对 None 进行 append()操作。
代码大致如下:
>>> a = [1, 2, 3]
>>> b = ("other", a.append(4))
>>> b[1].append(9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'append'
原因
append()方法的返回值为 None,而不是 list 对象本身。
>>> a = [1, 2, 3]
>>> b = ("other", a.append(4))
>>> print(a)
[1, 2, 3, 4]
>>> print(b)
('other', None)
>>> c = a.append(5)
>>> print(c)
None
>>> type(c)
<class 'NoneType'>
那为什么这个方法返回的是 None ,而不是列表本身呢?我对此感到十分的困惑。
官方文档中的解释
其实这个问题和为什么 list.sort() 返回 None 非常相似,我们可以通过阅读官方的设计和历史文档了解到其中的原因。
In situations where performance matters, making a copy of the list just to sort it would be wasteful. Therefore, list.sort() sorts the list in place. In order to remind you of that fact, it does not return the sorted list. This way, you won’t be fooled into accidentally overwriting a list when you need a sorted copy but also need to keep the unsorted version around.
Why doesn’t list.sort() return the sorted list?
大致说的是 list.sort()是对列表进行原地排序。这么设计的目的是,如果你也想保留并未排序的原来列表,这样可以防止你意外覆盖原来的列表。
Python 的设计原则
事实上,Python 的一般设计原则是,就地改变对象的函数(不创建新的对象)一律都返回 None 。Python 的设计者 Guido van Rossum 在下面的邮件中阐述了自己对此的观点。
I find the chaining form a threat to readability; it requires that the
reader must be intimately familiar with each of the methods. The
second form makes it clear that each of these calls acts on the same
object, and so even if you don’t know the class and its methods very
well, you can understand that the second and third call are applied to
x (and that all calls are made for their side-effects), and not to
something else.
[Python-Dev] sort() return value
大致意思是说 Method Chaining 降低了代码的可读性,并有造成错误的潜在威胁。
总结
在 Python 中就地改变对象的函数的返回值是 None 。除非清晰地了解函数的副作用,否做不要在代码中使用 Method Chaining。