sha*_*hef 7 python matlab functional-programming side-effects
我正在考虑从Matlab转到Python/numpy进行数据分析和数值模拟.我已经使用Matlab(和SML-NJ)多年了,并且在功能环境中非常舒适而没有副作用(除了I/O),但我对Python中的副作用有点不情愿.人们可以分享他们最喜欢的关于副作用的问题,如果可能的话,他们如何绕过它们?作为一个例子,当我在Python中尝试以下代码时,我有点惊讶:
lofls = [[]] * 4 #an accident waiting to happen!
lofls[0].append(7) #not what I was expecting...
print lofls #gives [[7], [7], [7], [7]]
#instead, I should have done this (I think)
lofls = [[] for x in range(4)]
lofls[0].append(7) #only appends to the first list
print lofls #gives [[7], [], [], []]
Run Code Online (Sandbox Code Playgroud)
提前致谢
混淆对相同(可变)对象的引用与对单独对象的引用确实是一个"陷阱"(受所有非功能语言的影响,具有可变对象的语言,当然还有引用).初学者的Python代码中经常出现的错误是滥用可变的默认值,例如:
def addone(item, alist=[]):
alist.append(item)
return alist
Run Code Online (Sandbox Code Playgroud)
如果目的是addone保持自己的状态(并将一个增长列表返回给连续的调用者),则此代码可能是正确的,就像static数据在C中工作一样; 如果编码器错误地认为每次通话都会产生一个新的空列表,那就不正确了.
用于函数式语言的原始初学者也可能被Python内置容器中的命令查询分离设计决策所混淆:没有特别返回的任何东西的变异方法(即绝大多数变异方法)都不会返回任何东西(具体而言,他们回归None) - 他们正在"就地"完成所有工作.来自误解的错误很容易被发现,例如
alist = alist.append(item)
Run Code Online (Sandbox Code Playgroud)
几乎可以肯定是一个bug - 它将一个项目附加到名称引用的列表中alist,然后将名称重新绑定alist到None(append调用的返回值).
虽然我提到的第一个问题是关于早期约束,可能会误导那些认为绑定是迟到的人,但是有些问题是另一种方式,有些人的期望是早期绑定,而绑定是相反,迟到了.例如(使用假设的GUI框架......):
for i in range(10):
Button(text="Button #%s" % i,
click=lambda: say("I'm #%s!" % i))
Run Code Online (Sandbox Code Playgroud)
这将显示十个按钮写着"按钮#0","按钮#1"等,但点击时,他们的每一个将say它#9-因为i 内lambda被后期绑定(用词汇关闭).修复是利用参数的默认值是早期绑定的事实(正如我指出的第一个问题! - )并将最后一行更改为
click=lambda i=i: say("I'm #%s!" % i))
Run Code Online (Sandbox Code Playgroud)
现在lambda的i是带有默认值的参数,而不是一个自由变量(抬头词法关闭)更多,因此代码按预期工作(还有其他的方法也一样,当然).