如何在Python中声明实例变量的默认值?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (122)

是否应该给类成员这样的默认值:

class Foo:
    num = 1

或者像这样?

class Foo:
    def __init__(self):
        self.num = 1

在这个问题我发现在这两种情况下,

bar = Foo()
bar.num += 1

是一个定义明确的操作。

我知道第一个方法会给我一个类变量,而第二个方法不会。但是,如果我不需要类变量,而只需要为我的实例变量设置一个默认值,那么这两个方法是否都一样好呢?或者他们中的一个比另一个更“琵琶”?

我注意到的一件事是在Django教程中,他们使用第二种方法来声明模型。就我个人而言,我认为第二种方法更优雅,但我想知道什么是“标准”方式。

提问于
用户回答回答于

首先,这没问题:

>>> class TestB():
...     def __init__(self, attr=1):
...         self.attr = attr
...     
>>> a = TestB()
>>> b = TestB()
>>> a.attr = 2
>>> a.attr
2
>>> b.attr
1

但是,这只适用于不可变(不可更改)类型。如果默认值是可变的(意味着可以替换它),则会发生以下情况:

>>> class Test():
...     def __init__(self, attr=[]):
...         self.attr = attr
...     
>>> a = Test()
>>> b = Test()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[1]
>>> 

注a和b都有一个共享属性。这通常是不需要的。

这是定义实例变量默认值的Pythonic方法,当类型是可变的时:

>>> class TestC():
...     def __init__(self, attr=None):
...         if attr is None:
...             attr = []
...         self.attr = attr
...     
>>> a = TestC()
>>> b = TestC()
>>> a.attr.append(1)
>>> a.attr
[1]
>>> b.attr
[]

我的第一个代码片段之所以工作,是因为Python使用不可变的类型,在任何时候都会创建一个新的实例。如果您需要添加1到1,Python会为您生成一个新的2,因为旧的1不能更改。我想,这主要是因为散列的原因。

用户回答回答于

这两个片段所做的事情是不同的,所以这不是品味的问题,而是在你的环境中什么是正确行为的问题。Python文档解释了两者之间的差异,但以下是一些示例:

证物A

class Foo:
  def __init__(self):
    self.num = 1

这结合了num敬福实例...。对此字段的更改不会传播到其他实例。

因此:

>>> foo1 = Foo()
>>> foo2 = Foo()
>>> foo1.num = 2
>>> foo2.num
1

展览B

class Bar:
  num = 1

这结合了num敬福...。改变被传播!

>>> bar1 = Bar()
>>> bar2 = Bar()
>>> bar1.num = 2 #this creates an INSTANCE variable that HIDES the propagation
>>> bar2.num
1
>>> Bar.num = 3
>>> bar2.num
3
>>> bar1.num
2
>>> bar1.__class__.num
3

实际答案

如果我不需要一个类变量,而只需要为我的实例变量设置一个默认值,那么这两个方法是否都一样好呢?或者他们中的一个比另一个更“琵琶”?

证据B中的代码显然是错误的:为什么要将类属性(实例创建的默认值)绑定到单个实例?

证物A里的密码没问题。

但是,如果要在构造函数中为实例变量提供默认值,我将这样做:

class Foo:
  def __init__(num = None):
    self.num = num if num is not None else 1

...甚至:

class Foo:
  DEFAULT_NUM = 1
  def __init__(num = None):
    self.num = num if num is not None else DEFAULT_NUM

...甚至:(更好,但前提是,只有当你在处理不可变的类型!)

class Foo:
  def __init__(num = 1):
    self.num = num

这样你就可以做到:

foo1 = Foo(4)
foo2 = Foo() #use default

扫码关注云+社区

领取腾讯云代金券