鱼C论坛

 找回密码
 立即注册
查看: 670|回复: 4

[已解决]__new__()优势在哪里?学不下去了

[复制链接]
发表于 2024-2-24 14:17:59 | 显示全部楼层 |阅读模式

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

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

x
关于__new__()这个魔法方法,小甲鱼在书中写道

‘就是当继承一个不可变的类型的时候,它的特性就显得尤为重要了’

举出例子:
class CapeStr(str):
    def __new__(cls, string):
        string = string.upper()
        return str.__new__(cls, string)

a = CapeStr('I love FishC.com')
a
'I LOVE FISHC.COM'

我在询问AI 时,它告诉我:无论是在__new__()方法中还是在__init__()方法中修改不可变对象的值,都只会创建一个新的对象并返回,而不会改变原对象的值。要修改不可变对象的值,需要创建一个新的对象并重新赋值。


我的理解是   __new__() 在对象实例化的同时赋值string这个属性并大写处理,那么这让我联想到 __init__() 也是这样做的呀

我是不是可以这样:

class Capestr_new:
    def __init__(self, string):
        self.string = string.upper()

c = Capestr_new('I love FishC.com')
c.string
'I LOVE FISHC.COM'

如果都是创建新的对象,那么 __new__()对不可变对象修改的优势在哪里?

我知道我对 __new__()的看法是有问题的, 这是我不能继续学下去的原因,这里把我弄糊涂了,希望有大佬帮我解惑?
最佳答案
2024-2-24 14:47:11
本帖最后由 歌者文明清理员 于 2024-2-24 16:09 编辑

Python 变量分为可变和不可变。

首先了解 Python 的对象储存机制:

举例:
a="str"
a=a+"ing"

这样其实是在 "str"(字符串)上面贴了一个 a(变量名),然后把 "str" 上的 a 扔了,把 a 贴到 "str" + "ing" ("string") 上了。

也就是说创建了一个新的字符串。str 是不可变量
a = []
a.append(1)

这就不一样了:创建 [](列表),然后贴上 a,再在 [] 里塞进去一个 1。

所以这是同一个列表。list 是不可变量

__new__ 的用法如下:
class MyString(str):
    def __new__(cls, string):
        print("new")
        self = super().__new__(cls, string) # 这一步其实调用了父类 str 的方法
        return self
    def __init__(self, string):
        print("init")

看看上面的代码,再在终端里运行下,就懂了。

new 的优势(更正):在使用不可变量作为父类时,使用 new 会调用父类的方法生成 self。这避免了 str 的子类(应该是不可变量)变成可变的,从而引发 bug。

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2024-2-24 14:18:22 | 显示全部楼层
其实,你对于`__new__()`方法和`__init__()`方法的理解基本是正确的,它们都可以在对象实例化时进行一些初始化的操作。不过,它们有一个很大的区别。

`__init__()`是在对象已经被创建之后被调用的,它的主要作用是对已经存在的对象进行初始化操作,比如给对象的属性赋值等等。

而`__new__()`方法是在对象实例化之前被调用的,它的作用是创建一个新的对象。如果你想要自定义一个不可变的类型,比如字符串类型,你可以通过重写`__new__()`方法来实现。在重写之后,你可以在`__new__()`方法中对传入的字符串进行修改,然后返回一个新的字符串对象。

相比之下,如果你在`__init__()`方法中进行修改操作,那么实际上你并没有修改原来的对象,而是创建了一个新的对象来代替原来的对象。这样做虽然也能达到修改的效果,但是会导致原来的对象消失,因为你没有将新创建的对象赋值给任何变量。所以,如果需要对不可变对象进行修改,最好的方式还是使用`__new__()`方法。

总结一下,`__new__()`方法适用于需要自定义创建对象的场景,比如不可变类型和单例模式等;而`__init__()`方法则适用于对已有对象进行初始化的场景。

希望这样讲解可以帮助你更好地理解`__new__()`方法和`__init__()`方法的区别。加油,你一定能够继续学下去的!如果还有疑问,请随时提问哦!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-2-24 14:37:04 | 显示全部楼层
FishC 发表于 2024-2-24 14:18
其实,你对于`__new__()`方法和`__init__()`方法的理解基本是正确的,它们都可以在对象实例化时进行一些初 ...

所以在__new__()没有执行前,传入的数据还不是对象,比如这个‘ I  love FishC.com' 还不是对像,我这样理解对吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-2-24 14:37:17 | 显示全部楼层
水中有明月 发表于 2024-02-24 14:37
所以在__new__()没有执行前,传入的数据还不是对象, ...


是的,你的理解是正确的。在`__new__()`方法被执行之前,传入的数据并不是一个对象,通常是一个原始的数据类型,比如字符串、整数等。而`__new__()`方法就是用来将这些原始数据转化为对象的。在`__new__()`方法中,你可以对传入的数据进行处理,并创建一个新的对象来代表这个数据。这个新的对象可以是你自定义的类型,也可以是内置的类型,比如字符串类型。所以,在`__new__()`方法中,你可以对传入的字符串进行一些操作,比如大写处理等。然后,你可以通过调用`str.__new__(cls, string)`来创建一个新的字符串对象,并将处理后的字符串作为参数传递进去。最后,`__new__()`方法会返回这个新创建的对象。这样,在实例化的时候,你就得到了一个经过处理的新对象了。希望这样的解释能够帮助你更好地理解`__new__()`方法的作用。如果还有疑问,请随时提问哦!加油!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-2-24 14:47:11 | 显示全部楼层    本楼为最佳答案   
本帖最后由 歌者文明清理员 于 2024-2-24 16:09 编辑

Python 变量分为可变和不可变。

首先了解 Python 的对象储存机制:

举例:
a="str"
a=a+"ing"

这样其实是在 "str"(字符串)上面贴了一个 a(变量名),然后把 "str" 上的 a 扔了,把 a 贴到 "str" + "ing" ("string") 上了。

也就是说创建了一个新的字符串。str 是不可变量
a = []
a.append(1)

这就不一样了:创建 [](列表),然后贴上 a,再在 [] 里塞进去一个 1。

所以这是同一个列表。list 是不可变量

__new__ 的用法如下:
class MyString(str):
    def __new__(cls, string):
        print("new")
        self = super().__new__(cls, string) # 这一步其实调用了父类 str 的方法
        return self
    def __init__(self, string):
        print("init")

看看上面的代码,再在终端里运行下,就懂了。

new 的优势(更正):在使用不可变量作为父类时,使用 new 会调用父类的方法生成 self。这避免了 str 的子类(应该是不可变量)变成可变的,从而引发 bug。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-23 05:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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