鱼C论坛

 找回密码
 立即注册
查看: 1131|回复: 12

[已解决]魔法方法__new__和__init__之间的参数传递

[复制链接]
发表于 2019-4-19 20:36:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 jiangyangcn 于 2019-5-7 00:31 编辑

先贴一段python第43讲课后作业的代码,举个栗子:

class Word(str):

    def __new__(cls,arg):
        if ' ' in arg:
            arg = arg.partition(' ')[0]
        return str.__new__(cls,arg)

    def __init__(self,arg):
        print(arg)
        self.len = len(arg)

来看看传入字符串没有空格的时候,结果:

1.png

支字符串含有空格,需要再__new__中修改字符串时,结果:
2.png


问题:

为什么__new__中被修改的参数无法传递到__init__?
从第二个结果可以看到,__init__函数得到的不是__new__函数修改过的参数,而是传入__new__函数的原本参数。我想要看到的是,__init__函数得到经过修改后的参数. 比如,w=Word("I love fishc.com“), 这一句,我希望看到直接打印的是"I",而不是“I love fishc.com”。既然不能得到想要的参数,我想问为什么会这样?

才网上查找了一番资料,__new__返回的是cls的实例对象,然后这个实例对象再调用cls的__init__啊?


一点点猜想:
刚刚拉了个搞机(手机)群的搞开发的群友讨论了一下。群友给了几点说法,很老道,也很套路。
1.你在__new__里改了arg,但是arg只在那个函数体里被更改了,等于就是传了个值
2.本身py有些东西就是莫名其妙的
3.要真的解释估计得去看解释器源码


我结合这位群友的看法,大概猜一下这个问题的原因。
1.Word类的__init__根本没有被生成的实例首先调用,该实例对象调用的是父类str的__init__。所以调用实例w也可以得到正确答案,"I"
2.然后,python才把Word的参数原原本本地传给了本类__init__进行初始化。所以初始化时,打印的不是正确答案,"I love Fishc.com"



最后,我会继续把这个问题挂几天(不超过一周),希望有想法可以交流。
最佳答案
1970-1-1 08:00:00
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-4-19 20:53:23 | 显示全部楼层

回帖奖励 +1 鱼币

不是传递了吗?
第二个W不是返回了你定义的方法结果吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-4-19 21:19:43 | 显示全部楼层
风丶少 发表于 2019-4-19 20:53
不是传递了吗?
第二个W不是返回了你定义的方法结果吗?

输入W是返回了正确结果,但这不是我疑惑的地方。

问题是,从第二个结果可以看到,__init__函数得到的不是__new__函数修改过的参数,而是传入__new__函数的原本参数。这才是我想问的问题,刚刚我没有把问题表述准确。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-19 21:52:24 | 显示全部楼层
def __init__(self,arg):
        print(arg)
        self.len = len(arg)
这里你设置了print(arg), 所以你在传入arg参数后,执行了__init__方法下的print,所以才会打印出传入的参数
而你给W赋值之后,再次调用,那么他的返回值就是__new__方法下面的return后面的代码,(因为__init__方法是没有返回值的)

以上是我个人看法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-20 11:24:24 | 显示全部楼层
本帖最后由 smoggy 于 2019-4-20 11:31 编辑

这是个好发现
我理解,确实先调用的 __new__方法,__new__返回一个已经建立好的实例给__init__方法,就是__init__方法的self,arg是你传入的参数,_new__方法原封不动传给__init__。希望有大侠能来给讲透彻。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-20 15:49:59 | 显示全部楼层
首先,__new__和__init__方法,new方法执行在init方法之前,
然后,我看下来,其实你的代码并没有问题,你所说的参数也正常传递了,
其实你最终不明白的地方是partition方法的使用,partition方法处理完字符串后返回的是一个元组,你new方法里明确写了arg为元组的第一个值,那后面传递给init方法的arg最终也只能是I了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-4-22 16:50:04 | 显示全部楼层
风丶少 发表于 2019-4-19 21:52
def __init__(self,arg):
        print(arg)
        self.len = len(arg)

小甲鱼说,类实例化,第一个调用的方法__new__这个魔法方法,然后才是__init__魔法方法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-4-22 16:57:12 | 显示全部楼层
万中山 发表于 2019-4-20 15:49
首先,__new__和__init__方法,new方法执行在init方法之前,
然后,我看下来,其实你的代码并没有问题,你 ...

你没有明白我的想问的问题。从第二个结果可以看到,__init__函数得到的arg参数不是__new__函数修改过的参数,而是原本传入__new__函数的参数。我想要看到的是,__init__函数得到经过修改后的参数. 比如,w=Word("I love fishc.com“), 这一句,我希望看到直接打印的是"I",而不是“I love fishc.com”。

既然不能得到想要的参数,我想问为什么会这样?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-4-22 17:00:14 | 显示全部楼层
smoggy 发表于 2019-4-20 11:24
这是个好发现
我理解,确实先调用的 __new__方法,__new__返回一个已经建立好的实例给__init__ ...

还是找不到答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-22 22:16:49 | 显示全部楼层

你打印一下__init__的self
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-23 17:02:29 | 显示全部楼层
我不知道
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-24 20:15:44 | 显示全部楼层
楼上是个明白人。
其实最大的误区是你的问题 “为什么__new__中被修改的参数无法传递到__init__?”
这个问题本身就是错的。
为什么
  1. 传递给 __new__() 的参数在之后会传到 __init__() 里?
复制代码

不知道你是从哪里听来或者看来的
从 __new__() 里传到 __init__() 里的是那个类实例,是 __new__() 运行后返回的那个东西,
由 __init__(self) 里的那个 self 所接收,至于传给 __new__() 的参数,为什么一定会/非得传给__init__()?  
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-26 18:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表