【问题标题】:python class variable not visible in __init__?python 类变量在 __init__ 中不可见?
【发布时间】:2009-07-01 21:25:34
【问题描述】:

这段代码产生了一条错误消息,我觉得很奇怪:

class Foo(object):
    custom = 1
    def __init__(self, custom=Foo.custom):
        self._custom = custom

x = Foo()

谁能给点启示?

【问题讨论】:

    标签: python


    【解决方案1】:

    Foo 不可见,因为您正在构建它。但是由于你和custom在同一个范围内,你可以说custom而不是Foo.custom

    class Foo(object):
        custom = 1
        def __init__(self, mycustom=custom):
            self._custom = mycustom
    

    但请注意,稍后更改 Foo.custom 不会影响随后创建的 custom 的值 Foos 请参阅:

    class Foo(object):
        custom = 1
        def __init__(self, mycustom=custom):
            self._custom = mycustom
    
    one = Foo()
    Foo.custom = 2
    two = Foo()
    print (two._custom)  # Prints 1
    

    通过使用哨兵默认值,你可以得到你想要的:

    class Foo(object):
        custom = 1
        def __init__(self, mycustom=None):
            if mycustom is None:
                self._custom = Foo.custom
            else:
                self._custom = mycustom
    
    one = Foo()
    Foo.custom = 2
    two = Foo()
    print (two._custom)  # Prints 2
    

    【讨论】:

    • 很好,除了与 None 的比较应始终通过is 完成。
    • “虽然这确实意味着稍后更改 Foo.custom 不会影响随后创建的 Foos 看到的 custom 的值”:值得指出的是,默认值的函数总是如此在创建函数时只创建和绑定一次,所以即使 if 可以引用 Foo.custom 作为默认值,但仍然会出现默认值不会改变的情况Foo.custom 已更改。
    • 为什么允许在 init 的主体中引用 Foo.custom 而不能在初始化列表中?在这两种情况下,“我们都在构建它”。
    • @rdm:当您运行 init 的主体时,您不再构建Foo。只有当您调用 init 时,函数体中对“Foo.custom”的引用才会真正尝试在 Foo 中查找“custom”。正如 Miles 在他的评论中指出的那样,当您 定义 init 时会查找默认参数。
    • @rdm:对全局变量的引用只有在计算包含它们的表达式时才会被解析。创建函数时评估参数默认值。函数的主体在调用时进行评估。 init 在创建 Foo 实例时调用,在 Foo 类创建之后。
    【解决方案2】:

    我们要做的是以下

    class Foo( object ):
        custom = 1
        def __init__( self, arg=None )
            self._custom = self.custom if arg is None else arg
    

    这绕过了名称Foo 是否已定义的令人困惑的问题。

    【讨论】:

    • 为什么会让人困惑?在创建实例之前,应该初始化类。 init 在创建实例时运行,因此类变量应该是可见的。
    • @rdm:请参阅 Miles 对我的回答的评论。默认参数是在函数创建期间确定的(即在这种情况下是在创建类期间),而不是在您调用它时。
    【解决方案3】:

    类体在定义其自身的类之前执行,因此默认参数值不能引用该类。只需将 custom 设为默认值(无类限定)即可。

    【讨论】:

      【解决方案4】:

      我收到以下错误:

      Traceback (most recent call last):
        Line 1, in <module>
          class Foo(object):
        Line 3, in Foo
          def __init__(self, custom=Foo.custom):
      NameError: name 'Foo' is not defined
      

      这是因为名称 Foo 正在被定义为 __init__ 函数被定义的过程中,并且当时不完全可用。

      解决方案是避免在函数定义中使用名称Foo(我还将custom参数重命名为acustom以区别于Foo.custom):

      class Foo(object):
          custom = 1
          def __init__(self, acustom=custom):
              self._custom = acustom
      x = Foo()
      print x._custom
      

      【讨论】:

      • 但是你知道你可以在 initbody 中引用 Foo.custom,而不仅仅是在初始化列表中。这让我觉得前后矛盾。
      • "我还将自定义参数重命名为 acustom 以将其与 Foo.custom 区分开来":这可能是一个好主意,但并非绝对必要,在 Python 中的某些情况下甚至是一个习惯用法让它们相同(主要是循环内的嵌套函数,例如 lambda x=x:...)
      猜你喜欢
      • 1970-01-01
      • 2011-07-30
      • 2013-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 2015-10-20
      相关资源
      最近更新 更多