调用图地址库。
项目描述
Ptera
Ptera是一种强大的方式,可用于为日志记录、调试和测试目的对代码进行测量。通过简单的调用ptera.probing()
,您可以
📖 阅读文档
安装
pip install ptera
示例
您可以使用Ptera观察程序中任何变量的赋值
from ptera import probing
def f(x):
y = 10
for i in range(1, x + 1):
y = y + i
return y
with probing("f > y").values() as values:
f(3)
# These are all the values taken by the y variable in f.
assert values == [
{"y": 10},
{"y": 11},
{"y": 13},
{"y": 16},
]
在上面的示例中,
- 我们使用选择器
f > y
选择 函数f
的变量y
。 - 我们使用
values()
方法获取一个列表,其中将逐步累积y
的值。 - 当在
probing
块内部调用f
时,将拦截对y
的赋值并将其追加到列表中。 - 当
probing
块完成后,将移除测量并使f
恢复其正常行为。
创建测量
ptera.probing
:在with
块内测量变量。ptera.global_probe
:激活全局探测。
使用探测
Ptera的探测接口受到函数式响应式编程的启发,与giving(本身基于rx
)的接口相同。请在此处查看操作符的完整列表。
如果您想保持简单,并仅获取值列表,则始终可以使用with probing(...).values()
,如上例所示。您还可以使用with probing(...).display()
来打印值。
除此之外,您还可以定义复杂的数据处理管道。例如
with probing("f > x") as probe:
probe["x"].map(abs).max().print()
f(1234)
上面的代码定义了一个管道,该管道提取x
的值,对每个元素应用abs
函数,取这些绝对值的最大值,然后打印出来。请注意,这个语句在执行时并没有真正做任何事情,它只声明了一个管道,该管道将在之后的任何时候激活,当探测到的变量被设置时。这就是为什么在之后而不是之前调用f
的原因。
更多示例
Ptera致力于提供新的方法来检查程序正在做什么,所以所有示例都将基于这个简单的二分搜索函数
from ptera import global_probe, probing
def f(arr, key):
lo = -1
hi = len(arr)
while lo < hi - 1:
mid = lo + (hi - lo) // 2
if (elem := arr[mid]) > key:
hi = mid
else:
lo = mid
return lo + 1
##############################
# THE PROBING CODE GOES HERE #
##############################
f(list(range(1, 350, 7)), 136)
为了获取下表中右侧列的输出,需要在左侧列的代码插入到调用f
之前的大注释处。大多数global_probe
上的方法都定义了探测值将通过的管道(接口受到函数式响应式编程的启发),因此,在调用仪器化函数之前定义它们非常重要。
代码 | 输出 |
---|---|
global_probe("f > mid").display()
|
|
global_probe("f(mid) > elem").print("arr[{mid}] == {elem}")
|
|
减少操作很简单:提取键,并使用 global_probe("f > lo")["lo"].max().print("max(lo) = {}")
global_probe("f > hi")["hi"].min().print("min(hi) = {}")
|
|
使用 def unordered(xs):
return any(x > y for x, y in zip(xs[:-1], xs[1:]))
probe = global_probe("f > arr")["arr"]
probe.filter(unordered).fail("List is unordered: {}")
f([1, 6, 30, 7], 18)
|
|
累积到列表中 results = global_probe("f > mid")["mid"].accum()
f(list(range(1, 350, 7)), 136)
print(results)
或 with probing("f > mid")["mid"].values() as results:
f(list(range(1, 350, 7)), 136)
print(results)
|
|
探测
用法:with ptera.probing(selector) as probe: ...
选择器是我们想要通过探测器流经哪些函数中哪些变量的规范。其中一个变量必须是选择器的焦点,这意味着当那个变量被设置时,探测器将被触发。焦点可以表示为f(!x)
或f > x
(在两种情况下焦点都是x
)。
探测是rx.Observable的包装器,支持大量的操作符,如map
、filter
、min
、average
、throttle
等(接口与giving相同)。
示例1:中间变量
Ptera能够捕获函数中的任何变量,而不仅仅是输入和返回值
def fact(n):
curr = 1
for i in range(n):
curr = curr * (i + 1)
return curr
with probing("fact(i, !curr)").print():
fact(3)
# {'curr': 1}
# {'curr': 1, 'i': 0}
# {'curr': 2, 'i': 1}
# {'curr': 6, 'i': 2}
选择器上方的"!"表示焦点是curr
。这意味着它在curr
被设置时被触发。这就是为什么第一个结果没有i
的值。您可以使用选择器fact(!i, curr)
来关注i
。
with probing("fact(!i, curr)").print():
fact(3)
# {'i': 0, 'curr': 1}
# {'i': 1, 'curr': 1}
# {'i': 2, 'curr': 2}
您可以看到关联是不同的(当i
为2时,curr
为2,而当另一个选择器时为6),但这仅仅是因为现在它们是在i
被设置时触发的。
示例2:多个作用域
选择器可以在调用图中作用多个嵌套作用域。例如,选择器 f(x) > g(y) > h > z
会从三个不同函数的作用域中捕获变量 x
、y
和 z
,但仅当 f
调用 g
且 g
调用 h
时(无论是直接还是间接)。
def f(x):
return g(x + 1) * g(-x - 1)
def g(x):
return x * 2
# Use "as" to rename a variable if there is a name conflict
with probing("f(x) > g > x as gx").print():
f(5)
# {'gx': 6, 'x': 5}
# {'gx': -6, 'x': 5}
g(10)
# Prints nothing
示例 3:覆盖变量
还可以使用 override
(或 koverride
)方法来覆盖变量的值。
def add_ct(x):
ct = 1
return x + ct
with probing("add_ct(x) > ct", overridable=True) as probe:
# The value of other variables can be used to compute the new value of ct
probe.override(lambda data: data["x"])
# You can also use koverride, which calls func(**data)
# probe.koverride(lambda x: x)
print(add_ct(3)) # sets ct = x = 3; prints 6
print(add_ct(10)) # sets ct = x = 20; prints 20
重要: override() 只会覆盖 焦点变量。如前所述,焦点变量是位于 >
右侧的变量,或者以 !
为前缀的变量。Ptera 选择器只有在焦点变量被设置时才会触发,因此实际上它是有意义覆盖的唯一变量。
这一点值得记住,因为否则有时并不明显了解覆盖做了什么。例如
with probing("add_ct(x) > ct", overridable=True) as probe:
# The focus is ct, so override will always set ct
# Therefore, this sets ct = 10 when x == 3:
probe.where(x=3).override(10)
print(add_ct(3)) # sets ct = 10; prints 13
print(add_ct(10)) # does not override anything; prints 11
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。
源分发
构建分发
ptera-1.4.1.tar.gz 的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | ef54756245008cbd60a272312dc4bd0b7a93cd9c7b5963c198cb4ec18a8bd10a |
|
MD5 | 2ca5b5e9892ba7e88a965deaec1b1594 |
|
BLAKE2b-256 | 8000851bc533371011000216410e9cd3a167d90f74ae2c0cf2f84484026eecd0 |
ptera-1.4.1-py3-none-any.whl 的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 91b2d813b5a5534538d2f87452029194808e8bf415f834bd47e010008c2b5d21 |
|
MD5 | 74ada71f8a826579bbf6c4cfc00ab024 |
|
BLAKE2b-256 | 8dfd67fec9081aedd1e3f449706d3ae35b9f5bd3278c08abe43f77c2109bc923 |