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

如何在Python中使用exec()修改变量?函数内变量未更新问题

解决exec()无法修改外部变量passed的问题

你的代码中exec()无法修改外部的passed变量,核心原因是Python的作用域规则限制:在嵌套函数pass_check里,passed被视为局部变量,但exec()默认使用的命名空间不会直接修改这个局部变量——exec里的赋值操作只会修改自身临时命名空间中的passed,而不会同步到外部函数的passed变量上。

下面是几种可行的解决方法:

方法1:给exec传递显式的局部命名空间

通过给exec()传递第三个参数作为局部命名空间字典,手动同步变量值:

def get_random_persons_by_attributes(self, attributes, k):
    def pass_check(person):
        passed = True
        local_vars = locals()
        for att in attributes:
            exec(f"if not person.{att['attribute']} {att['operator']} {att['value']}: passed = False", globals(), local_vars)
            # 从命名空间字典中同步修改后的值
            passed = local_vars['passed']
        return passed
        
    print(pass_check(self.residents[0]))

方法2:替换exec为eval(更简洁)

避免使用exec,改用eval直接计算条件表达式,逻辑更清晰:

def get_random_persons_by_attributes(self, attributes, k):
    def pass_check(person):
        passed = True
        for att in attributes:
            # 计算条件是否成立
            condition = eval(f"person.{att['attribute']} {att['operator']} {att['value']}")
            if not condition:
                passed = False
                # 提前跳出循环优化性能
                break
        return passed
        
    print(pass_check(self.residents[0]))

方法3:完全避免exec/eval(最安全)

如果担心exec/eval的安全风险(比如传入恶意的属性字符串),可以通过解析属性路径+运算符映射的方式实现:

# 定义运算符映射字典
operator_map = {
    '==': lambda x, y: x == y,
    '!=': lambda x, y: x != y,
    '>': lambda x, y: x > y,
    '<': lambda x, y: x < y,
    '>=': lambda x, y: x >= y,
    '<=': lambda x, y: x <= y,
}

def get_random_persons_by_attributes(self, attributes, k):
    def pass_check(person):
        passed = True
        for att in attributes:
            # 解析嵌套属性路径(比如"age[\"age\"]")
            attr_str = att['attribute']
            current_val = person
            
            # 处理点分隔的属性
            for part in attr_str.split('.'):
                if '[' in part:
                    # 处理索引访问,比如age["age"]
                    attr_name, index_part = part.split('[', 1)
                    index = index_part.strip(']')
                    # 去除引号(如果是字符串索引)
                    if index.startswith(('"', "'")) and index.endswith(('"', "'")):
                        index = index[1:-1]
                    # 获取属性后再取索引
                    current_val = getattr(current_val, attr_name)[index]
                else:
                    # 直接获取属性
                    current_val = getattr(current_val, part)
            
            # 获取对应的运算函数
            op_func = operator_map.get(att['operator'])
            if not op_func:
                raise ValueError(f"不支持的运算符:{att['operator']}")
            
            # 判断条件
            if not op_func(current_val, att['value']):
                passed = False
                break
        return passed
        
    print(pass_check(self.residents[0]))

这种方法完全避免了动态执行字符串的风险,同时也不会出现作用域相关的问题,是更推荐的实现方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 06:31:02