听说面试官比较喜欢这些坑。该函数的默认参数是可变的。默认参数是最大的陷阱。演示如下:首先定义一个函数,传入一个列表,添加一个END,然后返回:defadd_end(L=[]):L.append('END')returnL调用时似乎可以正常工作通常:>>>add_end([1,2,3])[1,2,3,'END']>>>add_end(['x','y','z'])['x','y','z','END']当你用默认参数调用它时,一开始结果也是对的:>>>add_end()['END']但是,再次调用add_end()时,结果是错误的:>>>add_end()['END','END']>>>add_end()['END','END','END']很多初学者一头雾水,默认参数是[],但该功能似乎在上次添加“END”后“记住”了列表。原因解释如下:Python函数定义时,会计算默认参数L的值,即[],因为默认参数L也是一个变量,指向对象[],每次调用函数,如果L改变了内容,下次调用时,默认参数的内容会改变,不再是定义函数时的[]。定义默认参数时要记住一件事:默认参数必须指向不可变对象!要修改上面的例子,我们可以使用不可变对象None:defadd_end(L=None):ifLisNone:L=[]L.append('END')returnL现在,不管你调用多少次,不会有问题:>>>add_end()['END']>>>add_end()['END']在序列中存储同一个变量对象的多个引用如果你想复制一个序列的多个副本然后将它们拼接在一起,你可以将这个序列乘以一个整数,这个操作会产生一个新的序列:>>>l=[1,2,3]>>>l*3[1,2,3,1,2,3,1,2,3]如果在语句an中,序列a中的元素是对其他可变对象的引用,需要特别注意,因为这个公式的结果可能出乎意料。比如你想用my_list=[[]]3来初始化一个列表列表,但是你得到的列表中的3个元素实际上是3个引用,而这3个引用都指向同一个列表。这可能不是你想要的结果。让我们看看如何初始化列表列表。`#示例:一个包含3个列表的列表,3个嵌套列表中的每一个都有3个元素来表示井字游戏中的一行正方形>>>board=[['_']*3foriinrange(3)]>>>board[['_','_','_'],['_','_','_'],['_','_','_']]>>>board[1][2]='X'>>>board[['_','_','_'],['_','_','X'],['_','_','_']]#相当于下面的写法>>>board=[]>>>foriinrange(3):...row=['_']*3..。board.append(row)...>>>board[['_','_','_'],['_','_','_'],['_','_','_']]>>>board[2][0]='X'>>>board[['_','_','_'],['_','_','_'],['X','_','_']]这是另一种看起来很诱人的捷径,但实际上是错误的方法。>>>weird_board=[['_']*3]*3>>>weird_board[['_','_','_'],['_','_','_'],['_','_','_']]>>>weird_board[1][2]='O'>>>weird_board[['_','_','O'],['_','_','O'],['_','_','O']]#相当于下面的写法>>>row=['_']*3>>>board=[]>>>foriinrange(3):...board.append(row)包含对同一对象的3个引用的列表是无用的。当我们不进行更改时,一切看起来都很好。一旦我们尝试标记第1行和第2列的元素,我们立即暴露了列表中的3个引用指向同一个对象的事实。免费下载试用:https://support.i-search.com.cn/
