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

2016-06-16 14:45:09 +08:00
 sudo987

既然 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

求解。

3263 次点击
所在节点    Python
19 条回复
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
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
2016-06-16 15:30:34 +08:00
谢谢二位仁兄的回答,可能是我描述不清,是这样的,我们都知道__init__()是实例创建后执行的第一个方法,并且 python 没有赋值时的变量审查,所以我觉得在__init__()里对 self 赋什么值都是可以的,所以我想在__init__()对 self 进行赋值,让 self 变成一个完全不同的东西,诸如从 int 编程 float ,我觉得应该是可以的,但是结果却不是这样,求解。
SErHo
2016-06-16 15:37:37 +08:00
@sudo987 我的答案你看没有啊??你对 self 赋值的时候,赋值的 self 已经不是原来的 self 了。
sudo987
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
2016-06-16 15:42:54 +08:00
@SErHo 稍等,我再看下。
sudo987
2016-06-16 16:05:45 +08:00
@SErHo 谢谢提供链接,链接里给的例子很到位,”__new__()是真正的构造器,__init__()只是个初始化器“,这个说的比较好,可是具体“为什么”没有给出,而且您给出的通过 id()判断 self 似乎和我的问题关系不大,重新给 self 赋值,相当于改变 self 指针的指向,从 A 实例变成指向 42 ,可是,不管在不在__init__()做操作, id(self)前后的值肯定是不一样的。我不明白的是既然可以对 self 动态赋值,为什么不能改变 self 的指向(在 new 里面肯定可以,因为他是生成实例的地方),求解。
srlp
2016-06-16 16:07:10 +08:00
self 已经成为同名局部变量。
srlp
2016-06-16 16:08:53 +08:00
没有办法改变 self 的“指向”,因为此处没有类似 c 语言里面类似 *ptr 那种 dereference 操作符。
21grams
2016-06-16 16:29:02 +08:00
self 也能乱改的?
sudo987
2016-06-16 16:33:07 +08:00
@21grams 不关注实用性,只关注可能性。
mulog
2016-06-16 16:37:42 +08:00
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
2016-06-16 16:55:33 +08:00
你__init__中的 self 只是同名的变量,你并没有对实际的对象进行改变。本身对象的 self 应该不能修改吧
xiaolee59
2016-06-16 17:34:48 +08:00
所有在局部作用域内的重新赋值(其实是名字和值的绑定)都会使解释器将该名字看做是当前局部作用域内的局部变量,你给 self 赋值,“ self ”这个名字在__init__内就绑定到了 4.21 这个值,然而, self 的有效生命周期仅仅存在于__init__内,对传进来的对象无影响。
sudo987
2016-06-16 19:50:19 +08:00
@sxmman 多谢回复,纠正一下,任何类都是一个 type 这个准确,可任何对象都是从 type 继承来的,这个不对, object 是继承链的顶端,连 type 都是它的子类。
sudo987
2016-06-16 19:52:15 +08:00
@sxmman
object.__class__ = <type 'type'>
type.__bases__ = (<type 'object'>,)
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
2016-06-17 05:55:01 +08:00
我的理解是: self 是 instance 的 reference 。在__init__這個 scope 里你對 self 進行賦值,所以在__init__中有一個 local 的 self 。所以最後的結果是 instance 本身沒有被改變。

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

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

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

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

© 2021 V2EX