You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中延迟求值对象与普通值的统一响应问题求解

解决延迟求值对象与显式值行为一致的问题

你之前尝试修改实例的__class__来对齐行为的思路走不通——Python中大多数特殊操作符(比如+、-)是从类层面查找的,而非实例;如果延迟函数返回的类型动态变化,这种方法更是彻底失效。下面是更稳健的解决方案,通过代理模式让延迟求值对象完全模拟其求值结果的行为:

基础实现版本

import random

class DelayedEvaluation:
    def __init__(self, function):
        assert callable(function), f"Input argument {function} is not callable and can thus not be a delayed evaluation."
        self._delayed_func = function

    def _evaluate(self):
        """执行延迟函数并返回结果,抽离逻辑便于复用"""
        return self._delayed_func()

    def __repr__(self):
        return repr(self._evaluate())

    def __str__(self):
        return str(self._evaluate())

    # 代理所有未定义的属性/方法访问
    def __getattr__(self, name):
        evaluated_value = self._evaluate()
        return getattr(evaluated_value, name)

    # 实现加法操作(包括正向和反向,比如 1 + delayed 和 delayed + 1)
    def __add__(self, other):
        return self._evaluate() + other

    def __radd__(self, other):
        return other + self._evaluate()

    # 实现减法操作
    def __sub__(self, other):
        return self._evaluate() - other

    def __rsub__(self, other):
        return other - self._evaluate()

    # 实现乘法操作
    def __mul__(self, other):
        return self._evaluate() * other

    def __rmul__(self, other):
        return other * self._evaluate()

    # 按需添加其他操作符:比如 __truediv__ 除法、__lt__ 小于比较等

测试代码验证效果:

delayed_evaluation = DelayedEvaluation(lambda: 42)
print(delayed_evaluation)  # 输出: 42
print(delayed_evaluation + 1)  # 输出: 43
print(1 + delayed_evaluation)  # 输出: 43
print(delayed_evaluation.bit_length())  # 输出: 6(整数42的二进制位数)

for i in range(5):
    value = random.choice((DelayedEvaluation(lambda: 42), 43))
    print(value + 1)  # 无论是延迟实例还是显式值,都能正常输出43或44

进阶通用版本(自动生成操作符方法)

如果需要支持大量操作符,手动写每个方法太繁琐,可以用装饰器自动生成所有常见操作符的实现:

import random
import operator

def add_operator_methods(cls):
    """自动为类添加常见操作符的代理方法"""
    # 定义需要支持的操作符及其对应的特殊方法名
    operator_map = [
        ('add', '__add__', '__radd__'),
        ('sub', '__sub__', '__rsub__'),
        ('mul', '__mul__', '__rmul__'),
        ('truediv', '__truediv__', '__rtruediv__'),
        ('lt', '__lt__'),
        ('le', '__le__'),
        ('eq', '__eq__'),
        ('ne', '__ne__'),
        ('gt', '__gt__'),
        ('ge', '__ge__'),
        ('mod', '__mod__', '__rmod__'),
    ]

    for op_name, *method_names in operator_map:
        op_func = getattr(operator, op_name)
        for method_name in method_names:
            def create_proxy_method(op_func, is_reversed):
                def method(self, other):
                    evaluated = self._evaluate()
                    if is_reversed:
                        return op_func(other, evaluated)
                    return op_func(evaluated, other)
                return method
            # 判断是否是反向操作符(比如 __radd__)
            is_reversed = method_name.startswith('__r')
            setattr(cls, method_name, create_proxy_method(op_func, is_reversed))
    return cls

@add_operator_methods
class DelayedEvaluation:
    def __init__(self, function):
        assert callable(function), f"Input argument {function} is not callable and can thus not be a delayed evaluation."
        self._delayed_func = function

    def _evaluate(self):
        return self._delayed_func()

    def __repr__(self):
        return repr(self._evaluate())

    def __str__(self):
        return str(self._evaluate())

    def __getattr__(self, name):
        evaluated_value = self._evaluate()
        return getattr(evaluated_value, name)

核心原理说明

  1. _evaluate方法:统一处理延迟函数的执行,避免重复代码,保证每次操作都能获取最新的求值结果(如果你的延迟函数是动态的,比如返回随机数,这一点很重要)。
  2. __getattr__方法:当访问实例上不存在的属性或方法时,自动转发给求值后的结果。比如调用delayed.bit_length()时,会先求值得到42,再调用42的bit_length()方法。
  3. 操作符代理:对于+、-这类特殊操作符,Python会优先查找类定义的特殊方法(比如__add__),所以我们需要显式实现这些方法,将操作转发给求值后的结果。反向操作符(比如__radd__)是为了处理显式值 + 延迟对象的场景。

内容的提问来源于stack exchange,提问作者Adriaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:14:01