请教大家关于 python 类属性和实例属性的问题,谢谢!

2016-11-09 18:27:26 +08:00
 Tianny

code1

class Foo(object):
    x = 1.5

foo = Foo()

print Foo.x  # 值为 1.5 类属性
print foo.x  # 值为 1.5 ,实例属性(在实例属性没有的情况下,使用类属性)

foo.x = 1.7
print foo.x  # 实例属性
print Foo.x  # 实例属性的修改不会影响类属性(实例属性可以有效屏蔽类属性)

code2

#!/usr/bin/env python
# coding=utf-8


class Foo(object):
    x = {1: 'hello'}

foo = Foo()
print foo.x # 值为{1: 'hello'}
print Foo.x # 值为{1: 'hello'}

foo.x[1] = 'world'
print foo.x # 值为{1: 'world'}
print Foo.x # 值为{1: 'world'}

问题: 为什么第一个代码段当类属性是不可变对象时(数字),修改实例属性,不会影响到类属性 而第二个代码段中,当类属性是可变对象时(字典),修改实例属性,导致类属性也改变了?

1731 次点击
所在节点    Python
9 条回复
justou
2016-11-09 19:51:56 +08:00
这儿跟可变对象和不可变对象没啥关系;
类属性被所有实例共享, 实例都是从某个类(相当于模板)造出来的; 实例属性可各不相同, 还可以动态添加删除

这里是 foo.x=1.7 这种赋值方式的问题, 这会给实例动态添加一个(实例)属性 x, 跟类属性 x 不同
比如 print foo.y 会抛出 AttributeError, 但 foo.y=1 会动态添加一个实例属性 y

修改类属性用类名访问 Foo.x=2, 所有实例读取 x 属性时都是一样的值.(前提是没有被实例属性覆盖)

class Cls(object):
x = 1

c1 = Cls()
c2 = Cls()
print c1.x # 1
print c2.x # 1

Cls.x = 2
print c1.x # 2
print c2.x # 2

c1.x = 233
print c1.x # 233, 先得到实例属性
print c2.x # 2
print Cls.x # 2
justou
2016-11-09 19:56:58 +08:00
实例属性跟类属性是放在不同的字典里面的, print c1.x, c1.x = 233 这种操作就是字典操作
print c1.__dict__
print Cls.__dict__
blackeeper
2016-11-09 20:23:35 +08:00
楼上说的很对,实例属性跟类属性是放在不同的字典里面的。
foo 实例有两个字典:
1 、实例的字典 foo.__dict__
2 、类的字典 foo.__class__.__dict__
wisefree
2016-11-09 20:43:49 +08:00
'''python
#coding:utf-8

class Foo(object):
x = {1:'hello'}


foo = Foo()

foo.x[1] = 'world'
print(foo.__dict__)
'''
输出:
{}
说明, foo.x[1] = 'world',根本没有创建一个实例属性
bomb77
2016-11-09 20:44:27 +08:00
@justou
所以说楼主 code2 代码现象的原因是: foo.x[1] = 'world' ,因为 foo 实例本身没有实例属性 x ,且没有 x[1] = 'world' 创建变量的语法,所以 foo.x[1] = 'world' 修改了类属性 Foo.x

不知是不是这么理解?
wisefree
2016-11-09 20:45:16 +08:00
继续引发一点思考

```python
#coding:utf-8

class Foo(object):
x = {1:'hello'}


foo = Foo()

foo.x = {1:'world'}

print(foo.x)
print(Foo.x)


```

输出:
{1: 'world'}
{1: 'hello'}
Contextualist
2016-11-09 21:18:55 +08:00
我感觉上面各位都有些偏题了,造成这个现象的原因的确如楼主所说:字典是可变对象。
首先“实例属性的修改不会影响类属性”的确是对的
在实例属性没有的情况下,使用类属性,所以实例与类的 x 都是对那个字典的引用
但是 code2 中 foo.x[1] = 'world' 根本就**没有**修改或者创建实例属性,是 foo.x 的引用那个字典里的值被改变了, foo.x 的引用没变。然后因为实例与类的 x 都是对那个字典的引用,所以值相同
Tianny
2016-11-10 22:32:57 +08:00
@blackeeper 感谢!
Tianny
2016-11-10 22:33:53 +08:00
@wisefree 是的,例子很有说服力,一看就懂!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/319359

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX