【问题标题】:Why can't I change attribute of a class in Python为什么我不能在 Python 中更改类的属性
【发布时间】:2015-11-17 04:01:02
【问题描述】:

我们说classes 在 Python 中是可变的,这意味着您可以使用引用我们可以更改将反映在对象中的值。例如,

>>> A = [1, 2, 3]
>>> B = A
>>> B[2] = 5
>>> A
[1, 2, 5]

在这里我可以使用B 更改A 对象的值,因为list 是一个可变类型。我的问题是为什么我不能使用相同的概念更改以下类的属性:

class C:

    apple = 2

    def __init__(self):
        self.dangerous = 2

D = C # D is pointing to same class C

D().dangerous = 5 # changing the value of class attribute D

D().apple = 3 # changing the value of apple here

print D().apple

print D().dangerous

OUTPUT:
2
2

谁能解释为什么输出是22 而不是35,因为我们说这个类是mutable 类型。

更新:参考@zxq9 的答案,如果您在D=C 时看到下图,D 实际上指向的是同一个类,而不是您所描述的新对象。你能解释一下吗:

【问题讨论】:

  • 人们为什么要反对这个? OP 提出了一个非常明确的问题,只是没有意识到实例化对象和类定义之间的语法差异。
  • @zxq9 你能看到我更新的照片吗?
  • 是的,但是你仍然只是分配给类的一个临时实例,而不是类本身。我会玩弄这个并扩大我的答案以涵盖这个。记住 Python 是一件非常的好事。
  • 你太棒了。谢谢你:)

标签: python class object immutability mutable


【解决方案1】:

每次你在一个类之后放置括号,你就是在构造一个类的新实例对象。因此,您打印的东西是全新的,并没有反映您之前所做的短期任务。

这是一个示例(扩展以涵盖对 C 类的底层引用):

>>> class C:
...   red = 2
...   def __init__(self):
...     self.blue = 2
... 
>>> C.red
2
>>> C.blue
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'blue'
>>> C().red
2
>>> C().blue
2
>>> #OOOOH!
... 
>>> z = C()
>>> z.red
2
>>> z.blue
2
>>> D = C
>>> D.red
2
>>> D().red
2
>>> D().red = "over 9000!"
>>> D.red
2
>>> D.red = "No, really over 9000!"
>>> D.red
'No, really over 9000!'
>>> C.red
'No, really over 9000!'
>>> #OOOOOOHHHH!
...

请注意,当我分配D.red = "No, really over 9000!" 时,我们确实直接更改了类——因为那是引用类定义本身,而不是从它创建的实例化对象。另请注意,分配 D 的属性(副本)更改了 C(原始)的属性,因为在许多(但不是全部)情况下,Python 会通过引用进行此类分配,这意味着 D 确实是C 的别名,不是底层结构的副本。阅读 Python 的 deepcopy() 方法,了解更多关于这个特别令人吃惊的细节。

仔细浏览示例代码,注意引用 ClassName调用 ClassName() 之间的区别。第一个是通过变量名对类定义的引用——用于生成实例对象的蓝图,其中带有构造函数__init__()。第二个是__init__()调用,其返回值是定义它的类的实例对象。

这也是你可以这样做的原因:

def some_fun(another_fun, value):
    another_fun(value)

def foo(v):
    return v + v

def bar(v):
    return v * v

some_fun(foo, 5)
some_fun(bar, 5)

此功能使 Python 在构建功能抽象方面具有高度的灵活性。 (现在如果它有尾调用消除......)

【讨论】:

    【解决方案2】:

    这是一个有趣的例子。

    1. D().dangerous = 5这行会改变实例D()的“危险”属性;但是 print D().dangerous 行打印出 ANOTHER 实例 D() 的属性“dangerous”。
    2. D().apple = 3 将在实例 D()创建属性“apple”,因为此实例确实没有“苹果”属性。
    3. print D().apple 行将打印出类 D 的属性“apple”,因为实例 D()没有“苹果”属性。
    4. 通过实例更改类的属性“apple”的一种方法是使用 D().__class__.apple=3

    【讨论】:

      猜你喜欢
      • 2012-02-10
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 2017-05-09
      • 2015-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多