python类属性不能用作构造函数的参数?

Posted

技术标签:

【中文标题】python类属性不能用作构造函数的参数?【英文标题】:python class attribute cannot used as an argument for constructor? 【发布时间】:2015-12-22 02:28:11 【问题描述】:

在 python 3 中,我发现 class 属性可以用作__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

但是通过使用dot.expression,在初始化这个类时,解释器会报错:

文件 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 类的范围相关概念?

【问题讨论】:

请发布您实际获得的内容,无需手动编辑。带有&gt;&gt;&gt; 提示符的第二个代码示例看起来像是交互式 Python 会话的一部分,但回溯来自执行脚本。如果您以交互方式尝试过这段代码,您会发现是类定义引发了异常,而不是构造对象的调用。 @Duncan 感谢您的建议! 【参考方案1】:

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

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

请参阅 Martijn Pieters 的回复,了解如何实际处理此类依赖关系。

【讨论】:

这是 Python 3; 所有类自动继承自object 错过了开篇文章中的那个,感谢您指出。为了避免混淆,我已删除该位。【参考方案2】:

函数默认值在函数定义时设置,而不是在被调用时。因此,存储的不是表达式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

【讨论】:

以上是关于python类属性不能用作构造函数的参数?的主要内容,如果未能解决你的问题,请参考以下文章

面向对象3

python 构造器

遍历构造函数的参数

面对对象

为啥我不能将类构造函数参数设置为默认值?

python类的使用(类定义,构造器,类属性,方法)