使用Python Hypothesis构建递归复合策略时遇LazyStrategy下标错误
解决Hypothesis复合递归策略的TypeError问题
错误原因
使用@st.composite装饰的函数逻辑错误:复合策略函数的职责是生成具体的测试数据实例,而非返回Strategy对象。你的代码中直接返回了st.fixed_dictionaries(...)(这是一个LazyStrategy实例),导致测试函数拿到的不是预期的字典,而是策略本身,自然无法通过下标['type']访问属性。
修正后的代码
from classes import Example from hypothesis import given, strategies as st import re MAX_DEPTH = 3 all_types = ['a','b','c','d'] @st.composite def recursive_Example_strategy(draw, depth=0): # 定义各类型对应的value策略 value_strategies = { type_name: st.from_regex(r'^(?:[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*)?', fullmatch=True) for type_name in all_types } value_strategies['b'] = st.text(st.integers()) # 随机选择类型并生成对应value type_ = draw(st.sampled_from(all_types)) value = draw(value_strategies[type_]) # 处理递归operands逻辑 if depth >= MAX_DEPTH: operands = None else: operands = draw(st.lists(st.deferred(lambda: recursive_Example_strategy(depth + 1)), max_size=3)) # 直接返回构造好的字典实例 return { "type": type_, "value": value, "operands": operands, } @given(Example_dict=recursive_Example_strategy()) def test_get_value(Example_dict): example = Example(Example_dict['type']) example.update_from_dict(Example_dict) if example.type == 'a': assert example.get_int_value() == int(Example_dict['value']) elif example.type == 'b': extracted_num = int(re.sub(r'.*\((\d+)\).*', r'\1', Example_dict['value'])) assert example.get_int_value() == extracted_num
关键修正点
- 移除
st.fixed_dictionaries:复合策略函数直接构造并返回字典实例,而非策略对象。 - 用
draw()生成具体值:所有需要随机生成的内容(类型、value、operands列表)都通过draw()从对应策略中获取实际数据。 - 简化类型字段:已经通过
draw(st.sampled_from(all_types))拿到具体的type_值,无需再用st.just(type_)包装,直接使用该值即可。 - 保留
st.deferred递归逻辑:递归引用策略时,st.deferred用于避免循环定义问题,确保策略能正确初始化。
补充说明
未加@st.composite时代码正常,是因为当时函数直接返回Strategy对象,@given可以直接接受策略;但添加@st.composite后,函数语义变为生成具体测试实例,必须返回实际数据而非策略。
内容的提问来源于stack exchange,提问作者hadromi
相关产品推荐
相关产品推荐

