V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Tianny
V2EX  ›  Python

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

  •  1
     
  •   Tianny · 2016-11-09 18:27:26 +08:00 · 1715 次点击
    这是一个创建于 2932 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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'}
    

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

    9 条回复    2016-11-10 22:33:53 +08:00
    justou
        1
    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
        2
    justou  
       2016-11-09 19:56:58 +08:00   ❤️ 1
    实例属性跟类属性是放在不同的字典里面的, print c1.x, c1.x = 233 这种操作就是字典操作
    print c1.__dict__
    print Cls.__dict__
    blackeeper
        3
    blackeeper  
       2016-11-09 20:23:35 +08:00
    楼上说的很对,实例属性跟类属性是放在不同的字典里面的。
    foo 实例有两个字典:
    1 、实例的字典 foo.__dict__
    2 、类的字典 foo.__class__.__dict__
    wisefree
        4
    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
        5
    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
        6
    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
        7
    Contextualist  
       2016-11-09 21:18:55 +08:00 via iPad   ❤️ 2
    我感觉上面各位都有些偏题了,造成这个现象的原因的确如楼主所说:字典是可变对象。
    首先“实例属性的修改不会影响类属性”的确是对的
    在实例属性没有的情况下,使用类属性,所以实例与类的 x 都是对那个字典的引用
    但是 code2 中 foo.x[1] = 'world' 根本就**没有**修改或者创建实例属性,是 foo.x 的引用那个字典里的值被改变了, foo.x 的引用没变。然后因为实例与类的 x 都是对那个字典的引用,所以值相同
    Tianny
        8
    Tianny  
    OP
       2016-11-10 22:32:57 +08:00
    @blackeeper 感谢!
    Tianny
        9
    Tianny  
    OP
       2016-11-10 22:33:53 +08:00
    @wisefree 是的,例子很有说服力,一看就懂!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3830 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 10:36 · PVG 18:36 · LAX 02:36 · JFK 05:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.