Skip to main content
 首页 » 编程设计

python之函数参数名称中的类与嵌套类属性冲突

2025年05月04日20shangdawei

考虑这段代码:

def gee(bool_, int32, int64, str_): 
 
    class S: 
        bool_ = bool_ 
        int32 = int32 
        int64 = int64 
        str_ = str_ 
 
    return S 
 
gee(1, 2, 3, 4) 

运行会报错:

Traceback (most recent call last): 
  File "test_.py", line 36, in <module> 
    gee(1, 2, 3, 4) 
  File "test_.py", line 27, in gee 
    class S: 
  File "test_.py", line 28, in S 
    bool_ = bool_ 
NameError: name 'bool_' is not defined 

我不知道哪些范围/关闭规则适用于此。 nonlocal 修复了错误,但结果不是我所期望的:

def gee(bool_, int32, int64, str_): 
 
    class S: 
        nonlocal bool_, int32, int64, str_ 
        bool_ = None 
        int32 = None 
        int64 = None 
        str_ = None 
    print(bool_, int32, int64, str_ ) 
 
    return S 
 
g = gee(1, 2, 3, 4) 
g.bool_ 

输出:

None None None None 
Traceback (most recent call last): 
  File "test_.py", line 38, in <module> 
    g.bool_ 
AttributeError: type object 'S' has no attribute 'bool_' 

除了重命名,我还能做些什么来使第一个代码片段中的分配工作?为什么它会这样?因为有name = ...?为什么 Python 不在赋值前计算名称?

请您参考如下方法:

当类被编译时,使用与函数类似的规则来解析名称。因为类主体包含对 bool_ 变量的赋值,解释器将其视为类变量,因此当被要求在赋值右侧解析其值时,会在类命名空间中查找。

一种可能性是使它们成为实例变量,在 __init__ 方法中分配,将参数默认为调用 gee 时提供的值:

def gee(bool_, int32, int64, str_): 
 
    class S: 
        def __init__(self, bool_=bool_, int32=int32, int64=int64, str_=str_): 
            self.bool_ = bool_ 
            self.int32 = int32 
            self.int64 = int64 
            self.str_ = str_ 
 
    return S 
 
my_class = gee(1, 2, 3, 4) 
my_instance = my_class() 
 
print(my_instance.bool_) 

您应该会发现此代码打印出 1。这是可能的原因是命名参数使用标准(词法)范围规则解析值表达式,而参数名称本身在每次调用开始时被注入(inject)命名空间。

如果您改为使用以下形式的赋值将值绑定(bind)到类变量,您会发现代码也有效

S.bool_ = bool_ 

因为,在 __init__ 方法运行时,类名 S 已经绑定(bind)到词法封闭的命名空间中。即使值绑定(bind)到类,它们也可以相对于实例进行引用 - 因为它们不存在于那里,所以解释器会继续在实例的类中查找。

然而,无论哪种情况,都需要调用类来设置 __init__ 中的属性值。