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