如何利用Hypothesis生成长度依赖于另一生成参数的列表策略?
如何利用Hypothesis生成长度依赖于另一生成参数的列表策略?
嘿,我太懂你现在的困扰了——之前那种先生成最大长度列表再切片的方法,不仅慢得离谱,还触发了Hypothesis的健康检查提示,确实挺闹心的。其实你需要的是复合策略(composite strategies),这正是Hypothesis专门用来处理这种「参数互相依赖」场景的工具!
为什么之前的方法行不通?
你之前的思路是先造一个最长的列表再切片,本质上是让Hypothesis生成了大量不符合要求的候选数据,然后手动过滤掉多余部分。这种过滤行为会让Hypothesis做很多无用功:既拖慢了测试速度,又因为大部分生成的数据被丢弃,触发了它的健康检查机制——毕竟它会认为你在浪费生成资源。
正确解法:用@composite定义依赖策略
你可以用hypothesis.strategies.composite装饰器创建一个自定义策略,先生成整数x,再根据x的具体值生成长度恰好匹配的列表。这样生成的每一组数据都是完全符合要求的,没有任何过滤操作,自然解决了速度和健康检查的问题。
给你看个具体的代码示例:
from hypothesis import given, strategies as st # 示例被测函数(和你的需求一致) def your_target_function(x: int, l: list[float]) -> None: assert len(l) == x, "列表长度必须和x相等" # 定义复合策略 @st.composite def x_and_matching_length_list(draw): # 先生成x,你可以根据需求限定范围,比如正整数1到100 x = draw(st.integers(min_value=1, max_value=100)) # 再根据x生成长度严格等于x的float列表 matching_list = draw(st.lists(st.floats(allow_nan=False), min_size=x, max_size=x)) return x, matching_list # 编写单元测试 @given(x_and_matching_length_list()) def test_target_function(x, l): your_target_function(x, l)
这个方法的优势一目了然:
- 无过滤,速度拉满:每一次生成的列表长度都严格匹配
x,不需要丢弃任何数据,测试效率直接提升。 - 通过健康检查:因为没有过滤行为,Hypothesis不会再弹出那个烦人的警告。
- 数据更精准:你可以完全控制
x的取值范围,以及列表中float的生成规则(比如我上面加了allow_nan=False避免NaN干扰,你可以根据自己的需求调整)。
如果你的x有特殊取值限制(比如只能是偶数),直接在st.integers里做限定就行,复合策略会自动适配生成对应长度的列表。
备注:内容来源于stack exchange,提问作者Simon Peatman
相关产品推荐
相关产品推荐

