是否有Python静态分析工具可以检测函数参数何时发生变异,从而导致副作用?
that is
def foo(x):
x.append("x at the end")
当x是一个列表时,将更改调用范围x。
能否可靠地检测到这一点?我之所以问这个问题,是因为这样一个工具可以使我们更容易地遵循纯功能方法。
我认为可以使用装饰器来警告它(用于开发),但这不像静态分析那样可靠。
发布于 2014-12-10 23:29:17
如果foo
函数是用list
-but调用的,那么它会变异它的参数--如果它是用不同的东西调用的,它可能会引发异常,或者做一些不改变它的事情。
类似地,您可以编写一个每次调用len
时都会发生变异的类型,然后一个只打印其参数长度的函数就会变异它的参数。
更糟糕的是,如果您使用像+=
这样的运算符,它将对具有它的类型调用(通常是变异的) __iadd__
方法,比如list
,但是在不具有(非变异) __add__
方法的类型上调用(不变异)__add__
方法,比如tuple
。那么,在这种情况下你打算怎么做?
因此,如果传入迭代器,即使参数上的for
循环也会发生变异,但是(通常)如果传递序列,则不会发生变异。
如果您只想列出频繁变异的方法名称和操作符,并搜索它们,那么作为AST访问者编写它就不难了。但这会给你带来很多假阴性和假阳性。
这正是静态类型设计所要解决的问题。Python没有构建静态类型,但是可以在Python的基础上构建。
首先,如果使用Python3.x,可以使用注释来存储参数的类型。例如:
def foo(x: MutableSequence) -> NoneType:
x.append("x at the end")
现在您知道了,从它需要一个MutableSequence
(或一个list
)而不是一个Sequence
这一事实来看,它打算改变它的参数。而且,即使它现在没有这样做,将来的一些版本也可能会这样做,所以无论如何您都应该相信它的注释。
现在,您可以像在Haskell或ML中那样解决您的问题了:您的纯函数代码接受一个Sequence
,它用那个Sequence
调用函数,您只需要确保这些函数都没有定义为接受MutableSequence
,对吗?
最后那部分是最难的部分。Python并没有阻止我写这个:
def foo(x: Sequence) -> NoneType:
x.append("x at the end")
为此,您需要一个静态类型检查器。Guido一直在推动注释标准化,允许形象化静态检查器成为Python的半官方部分。它还没有完全完成,而且它的类型系统也不如典型的类型化函数式语言那么强大,但它可以很好地处理大多数Python代码,满足您的需要。但是mypy并不是唯一可用的静态类型检查器;如果您搜索,还有其他的。
无论如何,使用类型检查器,foo
函数将失败,并会出现一个错误,说明Sequence
没有这样的方法append
。另一方面,如果正确地将foo
定义为接受MutableSequence
,那么使用Sequence
调用它的函数代码就会失败,从而导致解释Sequence
不是MutableSequence
的子类型的错误。
https://stackoverflow.com/questions/27412550
复制相似问题