是否有工具可以静态分析python代码,以确定可变参数是否是更改(检测副作用)

是否有工具可以静态分析python代码,以确定可变参数是否是更改(检测副作用),python,functional-programming,Python,Functional Programming,是否有Python静态分析工具可以检测函数参数何时发生变化,从而产生副作用 that is def foo(x): x.append("x at the end") 当x是列表时,将更改调用范围x 这能可靠地检测到吗?我这样问是因为这样一个工具会使遵守纯功能方法变得更容易 我想可以使用装饰器来警告(用于开发),但这不如静态分析那么可靠 如果使用列表调用foo函数,则该函数将改变其参数,但如果使用不同的方法调用,则可能会引发异常,或执行不会改变它的操作 类似地,每次调用len时,您可以编

是否有Python静态分析工具可以检测函数参数何时发生变化,从而产生副作用

that is
def foo(x):
    x.append("x at the end")
当x是列表时,将更改调用范围x

这能可靠地检测到吗?我这样问是因为这样一个工具会使遵守纯功能方法变得更容易


我想可以使用装饰器来警告(用于开发),但这不如静态分析那么可靠

如果使用
列表调用
foo
函数,则该函数将改变其参数,但如果使用不同的方法调用,则可能会引发异常,或执行不会改变它的操作

类似地,每次调用
len
时,您可以编写一个自身发生变异的类型,然后一个只打印其参数长度的函数就会变异其参数

如果您使用像
+=
这样的运算符,则情况更糟,该运算符将对具有它的类型(如
列表
)调用(通常是变异的)
\uud\uud>方法,但对不具有它的类型(如
tuple
)调用(非变异的)
\uuud\uud>方法。那么,在这种情况下你打算怎么办

就这一点而言,如果在迭代器中传递,即使是参数上的
For
循环也会发生变异,但(通常)如果在序列中传递,则不会发生变异

如果您只想列出频繁变化的方法名和运算符,并搜索它们,那么作为AST访问者编写这些内容并不难。但这会给你带来很多假阴性和假阳性


这正是静态类型设计要解决的问题。Python没有构建静态类型,但是可以在Python之上构建

首先,如果您使用的是Python3.x,那么可以使用注释来存储参数的类型。例如:

def foo(x: MutableSequence) -> NoneType:
    x.append("x at the end")
现在,您知道,从它采用
可变序列
(或
列表
)而不是
序列
,这一事实可以看出,它打算改变其参数。而且,即使它现在不这样做,将来的一些版本也可能这样做,所以无论如何,您应该相信它的注释

现在你可以用Haskell或ML中相同的方法来解决你的问题:你的纯函数代码使用一个
序列
,它用这个
序列调用函数,你只需要确保这些函数都没有被定义为使用
可变序列
,对吗

最后一部分是最难的部分。Python并没有阻止我写以下内容:

def foo(x: Sequence) -> NoneType:
    x.append("x at the end")
为此,您需要一个静态类型检查器。Guido一直在推动注释标准化,以使静态检查器成为Python的半官方部分。它还没有完全完成,它的类型系统也没有典型的类型化函数语言强大,但它可以很好地处理大多数Python代码,满足您的需求。但是mypy并不是唯一可用的静态类型检查器;如果你搜索,还有其他的


无论如何,使用类型检查器,
foo
函数将失败,并出现一个错误,说明
Sequence
没有这样的方法
append
。另一方面,如果将
foo
正确定义为采用
可变序列
,使用
序列调用它的函数代码将失败,错误解释为
序列
不是
可变序列

的子类型,因为即使不知道
x
的类型,也不可能知道哪些方法或操作符发生了变异,更不用说该类型是如何定义的了(甚至可能是C),不可能有一个工具可以满足您的所有要求。更好的解决方案是使用静态类型检查。如果将
foo
定义为使用
列表
,或
可变序列
,那么您知道它打算变异
x
;如果定义为使用
序列
,则类型检查程序将不会o调用
x.append
失败,因为
Sequence
没有这样的方法。有多种静态类型检查程序,但它们之间没有太多的标准化。Guido想将其更改为3.5或3.6,他喜欢作为起点,所以您可能想先查看一下。谢谢。我将查看mypy。假设是class,像FrozenDict一样,不提供就地变异函数,MyPy可以静态地“强制”这一点,这可能是我们所期望的最好的。没错。这基本上是人们在类型化函数编程中使用的解决方案。实际上,这正是静态类型系统所需要的。(如果你在寻找一种魔力。)“从这个可变类型中生成一个不可变的类型”修饰符,比如C++或D的
const
——加上
const
所带来的所有问题,那么Python就不会有这样的问题,就像任何类型化方案或ML派生等一样。)静态类型检查器会阻止我这样做吗(在您的Foo函数中,它需要一个序列):x(2).FROBNICATE()(在这个方法中改变x第二个元素的状态),您会考虑Python可靠的静态类型检查器吗?@ Gerrat:这取决于类型系统的强大程度。MyPy处理简单的(java类)泛型,所以你可以<代码> DEFO(x:Stord[SPAM])。
,如果
垃圾邮件
是一个没有
Frobnite
方法的不可变对象,您将得到一个错误。(这里的关键是,检查不可变类型比检查不可变使用的可变类型更容易。因此,您可能需要定义不可变的
Spam
和可变子类型
FrobinatableSpam
——就像
Sequence
MutableSequence
)@Gerrat:不管怎样,如果您说的“可靠”是什么意思没有误报,除非你忘了