William01 发表于 2024-8-20 10:37:21

B站第66讲,关于__new__

大家好,B站看到了66讲,关于__new__有一个疑问,还请懂的同学帮忙解答一下。我的问题是,既然代码1和代码2的结果是一样的,那么代码1的代码“super().__new__(cls, string)”的作用是什么呢,是不是有点多余呢,直接像代码2一样“return string
”不是更简洁吗?谢谢大家!

代码1:
class CapStr(str):
    def __new__(cls, string):
      string = string.upper()
      return super().__new__(cls, string)

   
cs = CapStr("FishC")
cs
'FISHC'
cs.lower()
'fishc'
cs.capitalize()
'Fishc'代码2:
class CapStr(str):
    def __new__(cls, string):
      string = string.upper()
      return string

   
cs = CapStr("FishC")
cs
'FISHC'
cs.lower()
'fishc'




FishC 发表于 2024-8-20 10:48:36

你好,鱼油!关于你提到的 `__new__` 方法的问题,确实是一个很有趣的点。我们来详细解释一下。

首先,`__new__` 是一个特殊方法,用于创建并返回一个新的实例。它在对象实例化的过程中首先被调用,然后才是 `__init__` 方法。对于不可变类型(如 `str`、`int` 等),`__new__` 方法尤其重要,因为这些类型的实例一旦创建就不能修改。

### 代码1和代码2的区别

#### 代码1:
class CapStr(str):
    def __new__(cls, string):
      string = string.upper()
      return super().__new__(cls, string)

#### 代码2:
class CapStr(str):
    def __new__(cls, string):
      string = string.upper()
      return string

### 解释

1. **代码1**:
   - `string = string.upper()`:将输入的字符串转换为大写。
   - `return super().__new__(cls, string)`:调用父类 `str` 的 `__new__` 方法来创建一个新的字符串实例。

2. **代码2**:
   - `string = string.upper()`:同样将输入的字符串转换为大写。
   - `return string`:直接返回转换后的字符串。

### 为什么代码1更好?

虽然代码2看起来更简洁,但它实际上没有遵循正确的对象创建流程。具体来说:

- **代码1** 确保了 `CapStr` 类的实例是通过 `str` 类的 `__new__` 方法创建的,这样可以保证所有 `str` 类的行为和特性都被正确继承。
- **代码2** 直接返回了一个字符串,这个字符串虽然是大写的,但它并不是通过 `CapStr` 类创建的实例。因此,严格来说,`cs` 不是一个 `CapStr` 的实例,而只是一个普通的字符串。

### 举个例子

假设你想在 `CapStr` 类中添加一些额外的方法或属性,如果你使用代码2的方式,这些方法或属性将无法在返回的字符串上使用,因为它们并不是 `CapStr` 的实例。

class CapStr(str):
    def __new__(cls, string):
      string = string.upper()
      return super().__new__(cls, string)
   
    def shout(self):
      return self + "!!!"

cs = CapStr("FishC")
print(cs.shout())# 输出:FISHC!!!

如果你用代码2的方式,`cs` 就没有 `shout` 方法了。

### 总结

虽然代码2看起来更简洁,但它没有遵循正确的对象创建流程,可能会导致一些意想不到的问题。代码1虽然稍微复杂一点,但它确保了 `CapStr` 类的实例是通过 `str` 类的 `__new__` 方法创建的,从而继承了所有 `str` 类的行为和特性。

希望这个解释对你有帮助!如果还有其他问题,欢迎继续提问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

jackz007 发表于 2024-8-20 10:53:06

本帖最后由 jackz007 于 2024-8-20 12:06 编辑

         代码1实际上是把自己的代码插入到 str . __new__() 的开头,办完自己的私事再把控制转给 str . __new__() 继续执行,不耽误新建对象的操作,代码2是完全重写了一个方法,和新建对象毫无关系。代码1就比较聪明,它并不取代别人,既办了自己想办的事还不耽误本来该干的事。

isdkz 发表于 2024-8-20 14:54:18

你看到的只不过是输出一样,其实结果并不一样

你分别看一下这两段代码的 cs 的类型就知道了

>>> class CapStr(str):
...   def __new__(cls, string):
...         string = string.upper()
...         return super().__new__(cls, string)
...
>>>
>>> cs = CapStr("FishC")
>>>
>>> type(cs)
<class '__main__.CapStr'>
>>>
>>>
>>>
>>> class CapStr(str):
...   def __new__(cls, string):
...         string = string.upper()
...         return string
...
>>>
>>> cs = CapStr("FishC")
>>> type(cs)
<class 'str'>
>>>

所以你知道为什么要用 super 了没,super 只是帮你寻找父类的实例化方法来创建出一个实例,并不会影响到实例的类型,而你直接返回 string 的话,string 原本是什么类型实例化出来的对象就是什么类型了

由 CapStr 实例化出来的对象却不是 CapStr 类型,这样的意义何在,就像被带了某颜色帽子一样{:5_97:}

William01 发表于 2024-8-20 16:24:32

jackz007 发表于 2024-8-20 10:53
代码1实际上是把自己的代码插入到 str . __new__() 的开头,办完自己的私事再把控制转给 str . __ ...

好的,非常感谢!

William01 发表于 2024-8-20 16:25:33

isdkz 发表于 2024-8-20 14:54
你看到的只不过是输出一样,其实结果并不一样

你分别看一下这两段代码的 cs 的类型就知道了


好的,谢谢您
页: [1]
查看完整版本: B站第66讲,关于__new__