副作用陷入python/numpy?想要恐怖故事和狭隘逃脱

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)

提前致谢

Ale*_*lli 9

混淆对相同(可变)对象的引用与对单独对象的引用确实是一个"陷阱"(受所有非功能语言的影响,具有可变对象的语言,当然还有引用).初学者的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,然后将名称重新绑定alistNone(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)

现在lambdai是带有默认值的参数,而不是一个自由变量(抬头词法关闭)更多,因此代码按预期工作(还有其他的方法也一样,当然).