Comprehensions 列表错误,但 for 循环更正

Error in Comprehensions list but correct in for loop

我正在尝试使用 exec 和 Comprehensions 列表在 class 中创建静态变量:


class DictTranslator:
    
    def __init__(self):
        self.create_static_variables()

    def get_value(self, key):

        return self.dict_.get(key)
    
    def create_static_variables(self):
        [exec("self." + str(value) + " = " + str(key))   for key, value in self.dict_.items()]
        
    
class AppImportanceTranslator(DictTranslator):


    dict_ = {
        -1: 'Unknown',
        0: 'Gone',
        1: 'Foreground',
        2: 'ForegroundService'
    }

但是我有这个错误: NameError: name 'self' is not defined

但我可以将代码更改为:

class DictTranslator:
    
    def __init__(self):
        self.create_static_variables()

    def get_value(self, key):

        return self.dict_.get(key)
    
    def create_static_variables(self):
        for key, value in self.dict_.items():
            exec("self." + str(value) + " = " + str(key))
        
    
class AppImportanceTranslator(DictTranslator):


    dict_ = {
        -1: 'Unknown',
        0: 'Gone',
        1: 'Foreground',
        2: 'ForegroundService'
    }
    

而且这段代码是正确的。

有什么想法吗?

我的python版本是3.8.10

首先:

  • Don't use list comprehensions for side effects。您正在创建一个带有 None 引用的列表对象,然后再次丢弃它。那是对计算机资源的浪费。

    如果您只需要一个循环,请始终使用 for 循环。

  • 您可以使用 setattr() functionself 上设置属性。 exec()应该是最后的手段,因为它会让您面临各种性能和安全问题。

您可以使用:

for key, value in self.dict_.items():
    setattr(self, value, str(key))

实现同样的目标。

或者,给你的 class 一个 __getattr__ hook 并让它懒惰地查找属性:

def __getattr__(self, name):
    try:
        return str(self.dict_[name])
    except KeyError:
        # raise an AttributeError instead
        raise AttributeError(name) from None

__getattr__ 挂钩会为您的实例上未明确设置的任何属性调用。

现在,实际出了什么问题:

exec() 看不到 self 因为列表理解 是一个新范围 ,就好像你 运行:

def create_static_variables(self):
    def inner_function():
        for key, value in self.dict_.items():
            exec("self." + str(value) + " = " + str(key))
    inner_function()

在编译时,Python 可以看到 self.dict_.items() 中的 self 并将其绑定为闭包(从 create_static_variables() 调用的本地命名空间中获取它。但是 exec() 在编译时不会 运行,因此只能看到全局变量或局部变量。

您可以使用 exec(..., globals(), {"self": self}) 在新的本地名称空间中传递 self 绑定,以解决这个问题。