0

在 python 3 中,我发现类属性可以用作__init__()函数中的参数,如下所示:

文件 test.py:

class Foo:
    var1 = 23333
    def __init__(self, var=var1):
        self.var = var

在cmd中运行:

C:\Users\rikka\Desktop>py -3 -i test.py
>>> f1=Foo()
>>> f1.var
23333

但是通过使用点表达式,当初始化这个类时,解释器会报错:

文件 test2.py:

class Foo:
    var1 = 23333
    def __init__(self, var=Foo.var1):
       self.var = var

在cmd中运行:

C:\Users\rikka\Desktop>py -3 -i test2.py
Traceback (most recent call last):
  File "test2.py", line 1, in <module>
    class Foo:
  File "test2.py", line 3, in Foo
    def __init__(self, var=Foo.var1):
NameError: name 'Foo' is not defined

我只是不知道为什么解释器找不到名称'Foo',因为 Foo 是环境中全局框架中的名称。是否有一些我不完全理解的关于 python 类的范围相关概念?

4

2 回答 2

6

函数默认值是在函数定义时设置的,而不是在被调用时设置的。因此,var1存储的不是表达式,而是变量表示的23333var1定义函数时恰好是局部变量,因为在构建类时,类主体中的所有名称都被视为函数中的局部变量,但该名称Foo尚不存在,因为该类尚未完成构建。

改用哨兵,然后在函数体中确定 的当前值Foo.var1

def __init__(self, var=None):
    if var is None:
        var = Foo.var1
    self.var = var

None在这里用作哨兵,因为它很容易获得并且不经常需要作为实际值。如果您确实需要能够设置var为不同的(即非默认)值,请使用不同的单例哨兵:

_sentinel = object()

class Foo:
    var = 23333

    def __init__(self, var=_sentinel):
        if var is _sentinel:
            var = Foo.var1
        self.var = var
于 2015-09-24T13:07:03.560 回答
1

问题是您在构建过程中试图引用 Foo 。在Foo.__init__被定义的时刻,也就是Foo.var被评估的时刻,Foo还不存在(因为它的方法,即Foo.__init__它本身,还没有完全构造好)。

函数/方法默认参数在函数/方法定义期间解析。类仅在定义后可用。如果一个类方法定义(即参数)引用了类本身,你就会得到一个循环依赖。没有类就不能定义方法,没有方法就不能定义类。

请参阅 Martijn Pieters 关于如何实际处理此类依赖项的回复。

于 2015-09-24T13:32:43.717 回答