为什么我不能更改 Python 中 class 的属性
Why can't I change attribute of a class in Python
我们说 classes
在 Python 中是可变的,这意味着您可以使用引用我们可以更改将反映在对象中的值。例如,
>>> A = [1, 2, 3]
>>> B = A
>>> B[2] = 5
>>> A
[1, 2, 5]
这里我可以使用 B
更改 A
对象的值,因为 list
是可变类型。我的问题是为什么我不能使用相同的概念更改下面 class 的属性:
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
谁能解释为什么输出是 2
和 2
而不是 3
和 5
因为我们说 class 是 mutable
类型。
UPDATE:参考@zxq9 的回答,如果您在执行 D=C
时看到下图,D
实际上指向相同的 class 而不是一个新对象你描述过。你能解释一下吗:
每次在 class 之后放置括号时,您都在构建 class 的 新实例对象。所以你打印的东西是全新的,并没有反映你之前所做的短暂任务。
这是一个示例(扩展以涵盖对 class 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!"
时,我们 确实 直接更改了 class -- 因为那是引用 class 定义本身,而不是从中创建的实例化对象。另请注意,分配 D(副本)的属性会更改 C(原始)的属性,因为在许多(但不是所有)情况下 Python 通过引用 进行此类分配 ,这意味着 D 实际上是 C 的 别名 ,而不是基础结构的副本。阅读 Python 的 deepcopy() 方法,了解更多关于这个特别令人吃惊的细节。
仔细浏览示例代码,注意引用 ClassName
和调用 ClassName()
之间的区别。第一个是 reference 通过变量名到 class 定义——生成带有构造函数 __init__()
的实例对象的蓝图。第二个是 __init__()
的 调用 ,其 return 值是定义它的 class 的实例对象。
这也是您可以这样做的原因:
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 构建功能抽象提供了高度的灵活性。 (现在要是它有尾调用消除就好了……)
这是一个有趣的例子。
- 行D().dangerous = 5会改变实例D()的属性"dangerous";但是 print D().dangerous 行打印出 ANOTHER 实例 D()[ 的属性 "dangerous" =29=].
- D().apple = 3行将创建实例"apple"中的属性D() 因为这个实例没有属性 "apple".
- 行 print D().apple 将打印出 class D[=29= 的属性 "apple" ] 因为实例 D() 没有属性 "apple".
- 通过其实例更改 class 的属性 "apple" 的一种方法是使用 D()。__class__.apple=3
我们说 classes
在 Python 中是可变的,这意味着您可以使用引用我们可以更改将反映在对象中的值。例如,
>>> A = [1, 2, 3]
>>> B = A
>>> B[2] = 5
>>> A
[1, 2, 5]
这里我可以使用 B
更改 A
对象的值,因为 list
是可变类型。我的问题是为什么我不能使用相同的概念更改下面 class 的属性:
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
谁能解释为什么输出是 2
和 2
而不是 3
和 5
因为我们说 class 是 mutable
类型。
UPDATE:参考@zxq9 的回答,如果您在执行 D=C
时看到下图,D
实际上指向相同的 class 而不是一个新对象你描述过。你能解释一下吗:
每次在 class 之后放置括号时,您都在构建 class 的 新实例对象。所以你打印的东西是全新的,并没有反映你之前所做的短暂任务。
这是一个示例(扩展以涵盖对 class 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!"
时,我们 确实 直接更改了 class -- 因为那是引用 class 定义本身,而不是从中创建的实例化对象。另请注意,分配 D(副本)的属性会更改 C(原始)的属性,因为在许多(但不是所有)情况下 Python 通过引用 进行此类分配 ,这意味着 D 实际上是 C 的 别名 ,而不是基础结构的副本。阅读 Python 的 deepcopy() 方法,了解更多关于这个特别令人吃惊的细节。
仔细浏览示例代码,注意引用 ClassName
和调用 ClassName()
之间的区别。第一个是 reference 通过变量名到 class 定义——生成带有构造函数 __init__()
的实例对象的蓝图。第二个是 __init__()
的 调用 ,其 return 值是定义它的 class 的实例对象。
这也是您可以这样做的原因:
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 构建功能抽象提供了高度的灵活性。 (现在要是它有尾调用消除就好了……)
这是一个有趣的例子。
- 行D().dangerous = 5会改变实例D()的属性"dangerous";但是 print D().dangerous 行打印出 ANOTHER 实例 D()[ 的属性 "dangerous" =29=].
- D().apple = 3行将创建实例"apple"中的属性D() 因为这个实例没有属性 "apple".
- 行 print D().apple 将打印出 class D[=29= 的属性 "apple" ] 因为实例 D() 没有属性 "apple".
- 通过其实例更改 class 的属性 "apple" 的一种方法是使用 D()。__class__.apple=3