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
sudo987
V2EX  ›  Python

在__init__()对 self 重新赋值的疑惑

  •  
  •   sudo987 · 2016-06-16 14:45:09 +08:00 · 3437 次点击
    这是一个创建于 3083 天前的主题,其中的信息可能已经有所发展或是发生改变。

    既然 self 指的是实例,那么在__init__()中对 self 重新赋值,比如, self = 4.21 ,然后对实例对象进行打印,结果应该打印出 4.21 这个值,可实验结果却不是。

    class A(int):
        def __init__(self, t):
            self = 4.21
    
    a = A(34)
     print a # a = 34,而不是 4.21
    

    求解。

    19 条回复    2016-06-17 05:55:01 +08:00
    hitmanx
        1
    hitmanx  
       2016-06-16 15:16:38 +08:00
    python 我也是学习中,说错请见谅。
    1. self 相当与其它语言里的 this 指针吧, self=4.21 本来就是有问题的语句.
    2. 4.21 本来就不是浮点数,你注释里写的期待值是 4.21 肯定是不对的,当成功时应该期待的是 4 而不是 4.21
    3. 你需要显示给父类,也就是这里的 int 类进行初始化
    4. int 在 python 里是 immutable type,在这种情况下初始化父类时需要用__new__而不是__init__

    以上这些你稍微拿关键字搜一下就能出来了:
    http://stackoverflow.com/questions/3238350/subclassing-int-in-python
    http://stackoverflow.com/questions/2673651/inheritance-from-str-or-int

    #  int is immutable so you can't modify it after they are created, use __new__ instead

    class TestClass(int):
    def __new__(cls, *args, **kwargs):
    return super(TestClass, cls).__new__(cls, 4.21)

    print TestClass(34)
    SErHo
        2
    SErHo  
       2016-06-16 15:16:59 +08:00
    对 self 赋值的时候,其实是创建了一个新的局部变量,比如执行以下代码:

    >>> class A(int):
    ... def __init__(self):
    ... print id(self)
    ... self = 42
    ... print self
    ... print id(self)
    ...
    ...
    ...
    >>> a = A()
    4543469472
    42
    140376639849864

    给个链接: http://stackoverflow.com/questions/1015592/why-is-self-in-python-objects-immutable
    sudo987
        3
    sudo987  
    OP
       2016-06-16 15:30:34 +08:00
    谢谢二位仁兄的回答,可能是我描述不清,是这样的,我们都知道__init__()是实例创建后执行的第一个方法,并且 python 没有赋值时的变量审查,所以我觉得在__init__()里对 self 赋什么值都是可以的,所以我想在__init__()对 self 进行赋值,让 self 变成一个完全不同的东西,诸如从 int 编程 float ,我觉得应该是可以的,但是结果却不是这样,求解。
    SErHo
        4
    SErHo  
       2016-06-16 15:37:37 +08:00
    @sudo987 我的答案你看没有啊??你对 self 赋值的时候,赋值的 self 已经不是原来的 self 了。
    sudo987
        5
    sudo987  
    OP
       2016-06-16 15:41:23 +08:00
    @SErHo
    ```
    class A(int):
    pass
    a = A(45)
    print a # 45

    class B(int):
    def __init__(self, t):
    self = 45
    b = B(2)
    print b # 2 而不是 45
    ```
    sudo987
        6
    sudo987  
    OP
       2016-06-16 15:42:54 +08:00
    @SErHo 稍等,我再看下。
    sudo987
        7
    sudo987  
    OP
       2016-06-16 16:05:45 +08:00
    @SErHo 谢谢提供链接,链接里给的例子很到位,”__new__()是真正的构造器,__init__()只是个初始化器“,这个说的比较好,可是具体“为什么”没有给出,而且您给出的通过 id()判断 self 似乎和我的问题关系不大,重新给 self 赋值,相当于改变 self 指针的指向,从 A 实例变成指向 42 ,可是,不管在不在__init__()做操作, id(self)前后的值肯定是不一样的。我不明白的是既然可以对 self 动态赋值,为什么不能改变 self 的指向(在 new 里面肯定可以,因为他是生成实例的地方),求解。
    srlp
        8
    srlp  
       2016-06-16 16:07:10 +08:00
    self 已经成为同名局部变量。
    srlp
        9
    srlp  
       2016-06-16 16:08:53 +08:00
    没有办法改变 self 的“指向”,因为此处没有类似 c 语言里面类似 *ptr 那种 dereference 操作符。
    21grams
        10
    21grams  
       2016-06-16 16:29:02 +08:00 via Android
    self 也能乱改的?
    sudo987
        11
    sudo987  
    OP
       2016-06-16 16:33:07 +08:00
    @21grams 不关注实用性,只关注可能性。
    sxmman
        13
    sxmman  
       2016-06-16 16:41:34 +08:00
    @sudo987 为什么是 new 里面创建实例,因为涉及到元类 metaclass 的概念,任何对象的都是从 type 继承过来的,如果申明某一个类为子类的 metaclass ,且在父类中重载 __new__方法的话,可以控制实例的生成,但是其实还是 super(Parent, cls).__new__(cls)得到的,所以任何类的 parent 其实都是 type 。
    至于为什么 init 中改变 self 本身无效,我猜是这样的,传入的 self 是一个变量,他的值就是实例的指针,也就是 c 中的**p ,如果改变他的值,并没有把 *p 的值修改,所以修改无效。
    cxyfreedom
        14
    cxyfreedom  
       2016-06-16 16:55:33 +08:00
    你__init__中的 self 只是同名的变量,你并没有对实际的对象进行改变。本身对象的 self 应该不能修改吧
    xiaolee59
        15
    xiaolee59  
       2016-06-16 17:34:48 +08:00
    所有在局部作用域内的重新赋值(其实是名字和值的绑定)都会使解释器将该名字看做是当前局部作用域内的局部变量,你给 self 赋值,“ self ”这个名字在__init__内就绑定到了 4.21 这个值,然而, self 的有效生命周期仅仅存在于__init__内,对传进来的对象无影响。
    sudo987
        16
    sudo987  
    OP
       2016-06-16 19:50:19 +08:00
    @sxmman 多谢回复,纠正一下,任何类都是一个 type 这个准确,可任何对象都是从 type 继承来的,这个不对, object 是继承链的顶端,连 type 都是它的子类。
    sudo987
        17
    sudo987  
    OP
       2016-06-16 19:52:15 +08:00
    @sxmman
    object.__class__ = <type 'type'>
    type.__bases__ = (<type 'object'>,)
    RTNelo
        18
    RTNelo  
       2016-06-16 21:28:13 +08:00
    文档中的解释:
    https://docs.python.org/2/reference/datamodel.html#the-standard-type-hierarchy
    注意 Callable types 中 User-defined methods 的说明。

    另外建议把 Data Model 这一章看完。
    haoc
        19
    haoc  
       2016-06-17 05:55:01 +08:00
    我的理解是: self 是 instance 的 reference 。在__init__這個 scope 里你對 self 進行賦值,所以在__init__中有一個 local 的 self 。所以最後的結果是 instance 本身沒有被改變。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   994 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 22:59 · PVG 06:59 · LAX 14:59 · JFK 17:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.