【问题标题】:Can I use a class attribute as a default value for an instance method?我可以使用类属性作为实例方法的默认值吗?
【发布时间】:2010-10-28 09:46:31
【问题描述】:

我想使用一个类属性作为我类的__init__ 方法的参数之一的默认值。不过,这个构造引发了NameError 异常,我不明白为什么:

class MyClass():
    __DefaultName = 'DefaultName'
    def __init__(self, name = MyClass.__DefaultName):
        self.name = name

为什么会失败,有没有办法做到这一点?

【问题讨论】:

  • 请务必阅读对Ethan's answer 的不太有用的公认答案,它提供了可让您执行此操作的有效语法。

标签: python


【解决方案1】:

那是因为,根据documentation

函数定义时计算默认参数值 被执行。 这意味着 表达式被计算一次,当 函数已定义

__init__()被定义时,MyClass的定义是不完整的,因为它还在被解析,所以你还不能引用MyClass.__DefaultName。解决此问题的一种方法是将特殊的唯一值传递给__init__(),例如None

def __init__(self, name=None):
    if name is None:
        name = MyClass.__DefaultName
    # ...

【讨论】:

  • 我宁愿不明确地按名称提及该类。从实例方法访问类和类属性的推荐方法是什么? type(self) 好吗?
【解决方案2】:

使用 Python 时要牢记的重要一点是何时执行不同的代码,以及classdef 语句在看到时执行。 em>,而不仅仅是存储起来以备后用。使用def 会更容易理解,因为唯一被执行的是()s 之间的任何内容——所以在上面的代码中

def __init__( SELF, name = MyClass.__DefaultName ):

当 Python 看到 MyClass.__DefaultName 时,它首先尝试在 local 命名空间中找到它,然后是模块(又名 global)命名空间,最后是在 builtins 中。

当执行class 语句时,local 命名空间是什么?这就是有趣的部分——它将成为 class 命名空间,但目前它是匿名的——所以你不能按名称引用它(在你的代码中又称为 MyClass),但你可以 直接引用已经定义的任何东西......以及已经定义了什么?在你的课堂例子中只有一件事——__DefaultName。所以你的__init__ 应该是这样的:

def __init__( SELF, name=__DefaultName ):

请记住,您不能在以后更改 MyClass._MyClass__DefaultName 并让这些更改显示在新实例中。为什么?因为__init__ def 只执行一次,而__DefaultName 在那一刻拥有的任何值都已被存储起来并将始终使用——除非您在创建新实例时直接指定新值:

my_instance = MyClass(name='new name')

【讨论】:

    猜你喜欢
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 2018-01-03
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    相关资源
    最近更新 更多