如何在Python脚本中查看哪些函数被调用以及所有变量值?
我刚刚发现了Python的不确定性软件包,我想弄清楚它是如何工作的,这样我就可以向老板解释了。
基本上,我看不出不确定性是如何实际计算的。这可能是因为我还不知道Python是如何工作的。
对于初学者,我如何查看c
是如何计算的?
import uncertainties
from uncertainties import ufloat
a = ufloat(1,3)
b = ufloat(2,4)
c = a + b # How does this work??
print c
如果您想了解如何计算,pdb
确实是一个解决方案。
然而,使用像pdb
这样的调试器,很难从高层了解正在发生的事情。这就是为什么阅读代码也很有用的原因。例如,如果您想知道a+b
的作用,可以检查type(a).__add__
是否存在,因为如果存在,它将处理添加。不确定性一揽子计划就是这样。
也就是说,__add__
确实是通过一种通用机制在不确定性中实现的,而不是专门编码的,所以我可以告诉你它实现背后的想法,因为这似乎是你最终想要的。
在您的示例中,a
和b
是Variable
对象:
>>> from uncertainties import ufloat
>>> a = ufloat(1, 3)
>>> b = ufloat(2, 4)
>>> type(a)
<class 'uncertainties.Variable'>
那么c = a + b
实际上是a
和b
的线性函数,由其相对于a
和b
的导数表示:
>>> c = a + b
>>> type(c)
<class 'uncertainties.AffineScalarFunc'>
>>> c.derivatives
{1.0+/-3.0: 1.0, 2.0+/-4.0: 1.0}
如果你知道一个函数相对于其变量的导数,你就可以很容易地从其变量的标准差中得到其标准差的近似值。
因此,实施不确定性一揽子计划背后的主要思想是,价值要么是:
- 以标准差描述的随机变量如x=3.14±0.0.1和y=0±0.01(
Variable
对象) - 或函数的线性近似(
AffineScalarFunc
对象:"仿射"因为它们是线性的,"标量"因为它们的值是实的,而"func"是因为它们是函数)
举一个更复杂的例子,z=2*x+sin(y)在(x,y)=(3.14,0)中近似为2*x+y。在实现中,由于近似是线性的,因此只存储关于变量的导数:
>>> x = ufloat(3.14, 0.01)
>>> y = ufloat(0, 0.01)
>>> from uncertainties.umath import sin
>>> z = 2*x + sin(y)
>>> type(z)
<class 'uncertainties.AffineScalarFunc'>
>>> z.derivatives
{3.14+/-0.01: 2.0, 0.0+/-0.01: 1.0}
因此,不确定性包所做的主要工作是计算任何涉及变量的函数的导数。这是通过自动微分的有效方法来实现的。具体来说,当您执行类似a+b
的操作时,Python会自动调用Variable.__add__()
方法,该方法通过计算a+b
相对于其变量的导数来创建一个新的线性函数(导数都是一,因为a
相对于a
的导数是一,对于b
也是一样)。更一般地,添加函数,而不是纯变量:f(a,b) + g(a,b)
相对于a
和b
的导数是用链式规则计算的。这就是自动微分的工作方式,这也是不确定性包中实现的内容。这里的关键函数是uncertainties.wrap()
。它是整个包中最大、最复杂的函数,但代码中有大量注释,并且提供了有关该方法的详细信息。
导数然后给出最终函数的标准差,作为变量标准差的函数(AffineScalarFunc.std_dev()
的代码非常简单:更困难的任务是自动计算导数)。
忽略uncertainties
模块的具体情况,Python提供了sys.settrace
函数,该函数可用于实现Smiliey应用程序跟踪器等功能
例如,来自文档:
在一个终端窗口中,运行监视器命令:
$ smiley monitor
在第二个终端窗口中,使用smiley来运行应用程序。这示例使用smiley源中testapp目录中的test.py树
$ smiley run ./test.py args: ['./test.py'] input = 10 Leaving c() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Leaving b() Leaving a()
监视器会话将显示执行路径和本地变量应用程序。
Starting new run: ./test.py test.py: 1: import test_funcs test.py: 1: import test_funcs test_funcs.py: 1: import sys test_funcs.py: 1: import sys test_funcs.py: 3: def gen(m): test_funcs.py: 8: def c(input):
您可以看看Python调试器:http://docs.python.org/2/library/pdb.html
正如您所知,调试器的设计目的是让您在执行过程中观察程序的各个部分的移动。
您可能还想在https://github.com/lebigot/uncertainties/