鱼C论坛

 找回密码
 立即注册
查看: 3608|回复: 20

[已解决]关于__new__我本来以为我懂了,结果并没有。。。

[复制链接]
发表于 2021-7-14 21:25:31 | 显示全部楼层 |阅读模式
8鱼币
class C2F(float):
    "摄氏度转换为华氏度"

    def __new__(cls, arg=0.0):
        return float.__new__(cls, arg * 1.8 + 32)
    def __init__(self,value):
        print (value)
a = C2F(32)
print (a)
最佳答案
2021-7-14 21:25:32
杨东明 发表于 2021-7-15 15:18
没懂__new__(cls,arg*1.8 + 32),第二个数据到底起的啥作用??print 不是相当于设置的__str__方法,第二 ...


没懂__new__(cls,arg*1.8 + 32),第二个数据到底起的啥作用?


计算好华氏度传给父类的 __new__ 后调利用父类 float 的 __new__ 来创建实例对象,简单来说就是创建了 用 float 类创建了个实例

print 不是相当于设置的__str__方法,第二个数据就相当于设置__str__??


__str__方法其实是在 print() 对象时调用,这里 print(value) 是调用 value 对象的 __str__ 而不是 C2F 类的 __str,但是因为 C2F 类是继承 float 的,所以也相当于是调用 float 的 __str__

还有就是可不可以解释一下继承父类,继承这些int,float啥的没理解到?


继承父类,子类保留父类的方法和属性,但是若你在字类中重写同名方法,会覆盖了父类的方法导致失去原有父类该同名方法的功能,但是你可以在同名方法中调用父类的该方法来保留父类原有的功能

int.__new__,float.__new__描述不都是返回一个实例对象吗??


不是的,__new__ 本质就是一个方法,也可以说是函数,因为在类中我们称为方法,又因为在 Python 中前后双下划线的方法被称为魔法方法,有特殊的功能和作用。这里 int.__new__,float.__new__ 返回的是实际上就是 int、float 的 __new__ 方法 的内存地址

__new__被调用时开辟一片内存空间,将一个变量引用这片内存空间就是返回一个实例对象的意思吗???


是的,__new__ 开辟内存,返回实例对象

最佳答案

查看完整内容

计算好华氏度传给父类的 __new__ 后调利用父类 float 的 __new__ 来创建实例对象,简单来说就是创建了 用 float 类创建了个实例 __str__方法其实是在 print() 对象时调用,这里 print(value) 是调用 value 对象的 __str__ 而不是 C2F 类的 __str,但是因为 C2F 类是继承 float 的,所以也相当于是调用 float 的 __str__ 继承父类,子类保留父类的方法和属性,但是若你在字类中重写同名方法,会覆盖了父类的 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-14 21:25:32 | 显示全部楼层    本楼为最佳答案   
杨东明 发表于 2021-7-15 15:18
没懂__new__(cls,arg*1.8 + 32),第二个数据到底起的啥作用??print 不是相当于设置的__str__方法,第二 ...


没懂__new__(cls,arg*1.8 + 32),第二个数据到底起的啥作用?


计算好华氏度传给父类的 __new__ 后调利用父类 float 的 __new__ 来创建实例对象,简单来说就是创建了 用 float 类创建了个实例

print 不是相当于设置的__str__方法,第二个数据就相当于设置__str__??


__str__方法其实是在 print() 对象时调用,这里 print(value) 是调用 value 对象的 __str__ 而不是 C2F 类的 __str,但是因为 C2F 类是继承 float 的,所以也相当于是调用 float 的 __str__

还有就是可不可以解释一下继承父类,继承这些int,float啥的没理解到?


继承父类,子类保留父类的方法和属性,但是若你在字类中重写同名方法,会覆盖了父类的方法导致失去原有父类该同名方法的功能,但是你可以在同名方法中调用父类的该方法来保留父类原有的功能

int.__new__,float.__new__描述不都是返回一个实例对象吗??


不是的,__new__ 本质就是一个方法,也可以说是函数,因为在类中我们称为方法,又因为在 Python 中前后双下划线的方法被称为魔法方法,有特殊的功能和作用。这里 int.__new__,float.__new__ 返回的是实际上就是 int、float 的 __new__ 方法 的内存地址

__new__被调用时开辟一片内存空间,将一个变量引用这片内存空间就是返回一个实例对象的意思吗???


是的,__new__ 开辟内存,返回实例对象
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-14 21:29:54 | 显示全部楼层
运行结果:  32    89.6
这个__new__不是应该返回的是实例对象吗??我是这么理解的,a= C2F(32),首先是__new__启用,更改数据,完成后相当于a = C2F(89.6)来设置实例对象,这时__init__启用,传入的value值为89.6,但是运行print(value)打印的32???还有就是a不是一个实例对象吗?打印出来为啥是一个数??
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-14 21:30:30 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-14 21:41:46 | 显示全部楼层
__new__不是给函数分配内存的吗,
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-14 21:42:34 | 显示全部楼层
杨东明 发表于 2021-7-14 21:29
运行结果:  32    89.6
这个__new__不是应该返回的是实例对象吗??我是这么理解的,a= C2F(32),首先是__ ...



是呀,__new__ 主要作用是开辟内存创建类的实例,以及将该实例对象和定义的参数都传递给 __init__。

另外,一个数也是一个实例呀,你忘记 type() 返回的时候都是什么 <class 'float'>、<class 'int'> 了么~

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-15 09:50:34 | 显示全部楼层
Twilight6 发表于 2021-7-14 21:42
是呀,__new__ 主要作用是开辟内存创建类的实例,以及将该实例对象和定义的参数都传递给 __init__。
...

我也没懂。。。。
大佬,我改了一下
class C2F(float):
    "摄氏度转换为华氏度"

    def __new__(cls, arg=0.0):
        print("=="*32)
        return type(float.__new__(cls, arg * 1.8 + 32))
    def __init__(self,value):
        print("++" * 32)
        print (value)
        print("++" * 32)
a = C2F(32)
print (a)

输出的结果是:
================================================================
<class '__main__.C2F'>

调试代码发现,他都没进去__init__()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-15 10:04:29 | 显示全部楼层
Twilight6 发表于 2021-7-14 21:42
是呀,__new__ 主要作用是开辟内存创建类的实例,以及将该实例对象和定义的参数都传递给 __init__。
...

然后,我又改了一下
class C2F(float):
    "摄氏度转换为华氏度"

    def __new__(cls, arg=0.0):
        print("==" * 32)
        return float.__new__(cls, arg * 1.8 + 32)
    def __init__(self,value):
        print("**"*32)
        print (value)
        self = value
        print("**" * 32)
a = C2F(32)
print("--" * 32)
print (a)


这样改了self后, 发现结果还是89.6?  这是为什么?  
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-15 12:11:06 | 显示全部楼层
本帖最后由 阿奇_o 于 2021-7-15 12:15 编辑

a = C2F(0)  意味着 __new__首先被调用,生成和返回相应的 实例对象(即 self),并传入 __init__(self, value) 的self ,
也就是 __new__ 总是先于 __init__ ,不然就没有 self (相关变量和内存没有开辟出来,没法做任何事) ,

另外一点是 __new__的参数 arg 就是  a = C2F(0) 中的 0 ,这0 同时也传给 __init__的value参数。

还有一点是 print(x) 实际上,是调用 x对象的特殊方法__str__() , 即 x.__str__()  
故你若要 “初始化”时,就看到 转化后的 华摄氏度,那就 可以直接 print(self),即相当于 print(self.__str__())
而 self 就是 __new__() 生成和返回的 转化后的float数据类型
>>> class c2f(float):
        def __new__(cls, arg=0.0):
                return float.__new__(cls, arg * 1.8 + 32)
        def __init__(self, value):
                print(value)

                
>>> a = c2f(0)
0
>>> type(a)
<class '__main__.c2f'>
>>> print(a)
32.0
>>> a.__str__()
'32.0'
>>> class c2f(float):
        def __new__(cls, arg=0.0):
                return float.__new__(cls, arg * 1.8 + 32)  # 调用float父类的__new__创建对象方法,返回一个转换为华氏度的浮点数 
        def __init__(self, value):
                print(self)   # self 就是 由__new__() 先生成的实例对象,然后传给 __init__()
                print(self.__str__())
                print(value)

>>> b = c2f(0)
32.0
32.0
0
>>> c = c2f(10)
50.0
50.0
10
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-15 13:30:56 | 显示全部楼层
阿奇_o 发表于 2021-7-15 12:11
a = C2F(0)  意味着 __new__首先被调用,生成和返回相应的 实例对象(即 self),并传入 __init__(self, va ...

  那为何  我在 __init__()中   
self  = value

外面在print(a)  得到结果还是  89.6?   
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-15 15:18:14 | 显示全部楼层
Twilight6 发表于 2021-7-14 21:42
是呀,__new__ 主要作用是开辟内存创建类的实例,以及将该实例对象和定义的参数都传递给 __init__。
...

没懂__new__(cls,arg*1.8 + 32),第二个数据到底起的啥作用??print 不是相当于设置的__str__方法,第二个数据就相当于设置__str__??我感觉把__new__拿掉,唯一有影响的就是print (a)。还有就是可不可以解释一下继承父类,继承这些int,float啥的没理解到。。我百度也似懂非懂得,int.__new__,float.__new__描述不都是返回一个实例对象吗??
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-15 15:37:13 | 显示全部楼层
Twilight6 发表于 2021-7-14 21:42
是呀,__new__ 主要作用是开辟内存创建类的实例,以及将该实例对象和定义的参数都传递给 __init__。
...

__new__被调用时开辟一片内存空间,将一个变量引用这片内存空间就是返回一个实例对象的意思吗???
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-15 15:59:04 | 显示全部楼层
本帖最后由 阿奇_o 于 2022-1-2 17:37 编辑
杨东明 发表于 2021-7-15 15:18
没懂__new__(cls,arg*1.8 + 32),第二个数据到底起的啥作用??print 不是相当于设置的__str__方法,第二 ...


其实你要先明白,背后它有很多“默认”会去执行的方法,
如 即使 你不写任何,单单写 class MyClass: pass
那么,当 obj = MyClass() , 也一样 会先调用 __new__() , 再 __init__() 等,只是 调用的是 其最终父类object类的__new__() 和 __init__() 以及打印是调用__str__()
但 你 class C2F(float): ...  就是继承float类,同时也继承object这个最大的总父类。

当 你 自己 “重写”__new__或__init__或__str__的特殊方法时, 就会 优先调用你写的,而不再往上找父类的
如 class C2F(float): ... 你直接继承float类,并调用了它的float.__new__(cls, ...) 于是它就按这个执行并返回给 你写的__init__(self, ...)  

至于参数的问题,__new__的 cls参数是固定的,且必须是放在第一个(这种叫“静态类方法”,知道怎么写就行了) arg只是个形参的名字
你可以换成value或任意合适唯一的名字,对应 先用类构造对象的实参,如 C2F(10)里的10,或 MyClass(10) ,
只不过你调用时,写 C2F(..)它直接提示和显示的形参是 __int__的形参名,你不能写别的形参名。。 比如,
>>> class c2f(float):
        def __new__(cls, value=0):
                return float.__new__(cls, value*1.8+32)
        def __init__(self, value):
                print(self)
                print(value)

                
>>> a = c2f(10)
50.0
10
>>> b = c2f(value=20)
68.0
20
>>> c = c2f(arg=20)   # 报错,你必须 用 __init__里定义的形参。即使你把__new__的形参改为叫 arg , 也会报错。
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    c = c2f(arg=20)
TypeError: __new__() got an unexpected keyword argument 'arg'
>>> 
由此可见,__new__的参数,除了 固定的cls,  其他参数 都来自 __init__的参数。

嗯,这个我也是 新发现:__new__的参数,除了固定的cls,  其他参数 都来自 __init__的参数

嗯,我应该讲明白了。。

-------------
补充:2022年1月2日17:26:59
现在仔细看看,这里关于参数的说法,其实是错误的。应该是 除cls外,__new__的其他参数会传给__init__。
这样就要求,当使用关键字参数时,必须它们所定义的形参名要相同。
否则,无法成功创建实例(这时__new__的参数错误),或无法完成初始化(这时__init__的参数错误)。

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-15 16:19:58 | 显示全部楼层
阿奇_o 发表于 2021-7-15 15:59
其实你要先明白,背后它有很多“默认”会去执行的方法,
如 即使 你不写任何,单单写 class MyClass:  ...

第一个def __new__(cls,arg),我大概明白,但是第二个__new__(cls,arg*1.8 + 32)他的第二个参数我没懂。。arg*1.8 +32他是怎么被print出来了??
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-15 16:24:42 | 显示全部楼层
阿奇_o 发表于 2021-7-15 15:59
其实你要先明白,背后它有很多“默认”会去执行的方法,
如 即使 你不写任何,单单写 class MyClass:  ...

这个返回的float.__new__(cls,arg*1.8+32)算实例对象的啥,a =c2f(10)def __new__调用,然后再调用float.__new__(cls,arg*1.8 +32),这个float的__new__开辟一片内存空间,但是第二个数据没有传给__init__,就是打印时才体现
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-15 16:28:17 | 显示全部楼层
阿奇_o 发表于 2021-7-15 15:59
其实你要先明白,背后它有很多“默认”会去执行的方法,
如 即使 你不写任何,单单写 class MyClass:  ...

__new__作用不是开辟内存空间,返回实例对象吗,开辟返回起作用的是第一个new函数还是父类的new函数??
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-15 22:49:57 | 显示全部楼层
本帖最后由 阿奇_o 于 2021-7-15 22:54 编辑
杨东明 发表于 2021-7-15 16:28
__new__作用不是开辟内存空间,返回实例对象吗,开辟返回起作用的是第一个new函数还是父类的new函数??


实例对象的确可以近似理解为“内存空间”,但这不是关键,关键你要理解它 被创造出来的过程……

我再补充一点吧,__new__ 必须 “正确地返回某个实例对象”(通常是父类的或其本类的 ),
像你 return type(...) 那就有问题了。导致__init__找不到self实例,故__init__根本没用执行下去。


另外,我觉得你对“重写”的概念都不理解,我多说也没用。。 你自己找文档、找例子,慢慢琢磨吧。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-7-16 10:07:26 | 显示全部楼层
Twilight6 发表于 2021-7-16 10:05
计算好华氏度传给父类的 __new__ 后调利用父类 float 的 __new__ 来创建实例对象,简单来说就是创 ...




难受,刚才回复打字打了十分钟

写了一堆解释,结果按到鼠标返回键

直接白写,上面重写了,描述更简洁些了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-17 21:30:50 | 显示全部楼层
Twilight6 发表于 2021-7-16 10:07
难受,刚才回复打字打了十分钟

写了一堆解释,结果按到鼠标返回键

懂了大佬,解释的挺好的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-7-17 21:31:20 | 显示全部楼层
阿奇_o 发表于 2021-7-15 15:59
其实你要先明白,背后它有很多“默认”会去执行的方法,
如 即使 你不写任何,单单写 class MyClass:  ...

感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-12 06:54

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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