鱼C论坛

 找回密码
 立即注册
查看: 1216|回复: 7

[技术交流] __new__方法的学习笔记

[复制链接]
发表于 2018-5-29 17:15:29 | 显示全部楼层 |阅读模式

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

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

x
__init__(self,...) 对实例化类对象进行初始化,可以带若干参数。该函数没有返回值,或者说返回 None  ,而不能返回数值或字符串等。
__new__(cls) 一个类实例化是最先引用的函数。

图1:小甲鱼演示的例子

图1:小甲鱼演示的例子

图1是小甲鱼在 41讲——构造与析构 章节 演示时候的例子。里面string的变量太多,搞的有点乱,然后自己又简单理了一下。
实际效果应该如下:
=======================================================================
class Capstr1(str):
    def __new__(cll,string1):
        string2 = string1.upper()
        return str.__new__(cll,string2)

a = Capstr1('i love fish1')

class Capstr2(str):
    def __new__(cll,string1):
        return str.__new__(cll,string1.upper())
   
b = Capstr2('i love fish2')


class Capstr3(str):
    def __new__(cll,string1):
        return super(Capstr3,cll).__new__(cll,string1.upper())

c = Capstr3('i love fish3')

print(a)
print(b)
print(c)
======================================================================
其中的cll是 __new__ 方法中的一个参数,并且是第一个参数,是当前正在实例化的类,可以改为其他名字,但是在定义类的时候,用到的时候始终要保持一致。string1是最后进行实例化的时候,Capstr1('i love fish1'),这里面传入的参数——也就是这个字符串 'i love fish1' 。
然后对string1进行大写操作,并把结果赋给string2,最后调用父类str的__new__方法,返回参数为string2的实例化的类对象。简洁写法如第二种!第三种写法中的super()方法暂时不知道什么意思和作用。这是模仿网站上别人的写法写的。最后效果是一样的。所以暂时写在这。

下面参照 http://www.jb51.net/article/85724.htm  摘抄如下:
__new__ 方法是什么?
如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参 数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 __new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。
__new__()方法的特性:
1.__new__()方法是在类准备将自身实例化时调用。
2.__new__()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
类的实例化和它的构造方法通常都是这个样子:
=======================================================================
class MyClass(object):
  def __init__(self, *args, **kwargs):
    ...
# 实例化
myclass = MyClass(*args, **kwargs)
=======================================================================
(里面的*args 和**kwargs参数,可以到网络上搜一下,很多解释。主要在于* 和**,这里附一个相应的链接: https://www.cnblogs.com/xuyuanyuan123/p/6674645.html)
正如以上所示,一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 __init__()方法之前,Python首先调用__new__()方法:
=======================================================================
def __new__(cls, *args, **kwargs):
  ...
=======================================================================
第一个参数cls是当前正在实例化的类。
如果要得到当前类的实例,应当在当前类中的__new__()方法语句中调用当前类的父类的__new__()方法。
例如,如果当前类是直接继承自object,那当前类的__new__()方法返回的对象应该为:
=======================================================================
def __new__(cls, *args, **kwargs):
  ...
  return object.__new__(cls)
=======================================================================
注意:事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时 ,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写 __new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。
__new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-5-29 17:18:23 | 显示全部楼层
刚学习python,希望大家多补充,纠正,一起学习和进步。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-7-3 20:22:24 | 显示全部楼层
一直没有理解这句话的意思 return str.__new__(cll,string2)
这是什么意思啊,不是应该这样写才对吗   return str().__new__(cll,string2)  加个括号才代表是实力话吗,才是返回对象吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-7-4 22:27:47 | 显示全部楼层
xue11 发表于 2018-7-3 20:22
一直没有理解这句话的意思 return str.__new__(cll,string2)
这是什么意思啊,不是应该这样写才对吗   re ...

我自己是这样理解的:
定义的这个 CapStr 这个类,的 __new__ 方法要返回一定的值,但是如果直接返回string2,像下面的话:
  1. class capstr(str):
  2.         def __new__(cll,string1):
  3.                 string2 = string1.upper()
  4.                 return string2
复制代码

也可以,最后的结果,如下:
  1. a = capstr('hello')
  2. a
  3. 'HELLO'
复制代码

但是,如果 输入  type(a) ,就会得到:
  1. type(a)
  2. <class 'str'>
复制代码

这是因为,string1.upper()  ,这个upper() 函数本身就是 str 类对象的方法,得到的结果也就是str 类的实例化类。因此这样得到的CapStr的实例化对象,还是 str 类,并没有起到我们重新定义类的目的。
因此我们需要,返回的时候,调用 CapStr 的父类 str 的__new__方法。来将 我们定义的__new__方法中大写后的字符串string2,给实例化。上面提到 cll 就是我们正在实例化的类。因此这样最后调用 CapStr 类实例化后的对象,就是CapStr类对象了。如下:
  1. class capstr(str):
  2.         def __new__(cll,string1):
  3.                 print(cll)
  4.                 string2 = string1.upper()
  5.                 return str.__new__(cll,string2)
复制代码

执行结果,打印出 cll 就是
  1. <class '__main__.capstr'>
复制代码

而实例化对象的类型也是:
  1. type(c)
  2. <class '__main__.capstr'>
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-7-4 22:52:12 | 显示全部楼层
xue11 发表于 2018-7-3 20:22
一直没有理解这句话的意思 return str.__new__(cll,string2)
这是什么意思啊,不是应该这样写才对吗   re ...

或者是分成两步来看,第一步就是:
  1. class capstr(str):
  2.         def __new__(cll,string1):
  3.                 string2 = string1.upper()
  4.                 return string2
复制代码

经过第一步后,string2就是大写字母了,然后 利用 str(string2),输出string2。当然在执行str(string2)的过程中肯定自然而然的调用 str 类的 __new__方法。
只不过我们实际在执行第二步的时候,直接利用他的 __new__ 方法,并且输入我们第一步的 cll 参数,这样就可以使输出的实例对象,类型为 capstr 了。

至于你最后说的,str.__new__(cll ,string2) 和 str().__new__(cll ,string2).这两个我试了一下,最后的效果,达到的目的是一样的。因为 str 是一个类,而 str()  结果是 ‘ ’,是 str 的一个实例对象,一个空字符串。无论是 str 类,还是 空字符串的实例对象,他们都可以调用 类本身的 __new__ 函数。就好比:
  1. str.isalnum('1')
  2. True
  3. a = str(1)
  4. a.isalnum()
  5. True
复制代码

isalnum() 是str类的一个函数,str 类本身可以调用,实例化的对象 a 也可以调用。而 __new__ 也是 str 的一个函数,只不过比较特殊而已。而我们最初讨论的问题里,最后只是想利用 str 的 __new__ 方法而已,前面是 str  还是 str() 都可以。我是这样理解的,不知道明白没有。[yunbei]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-7-4 23:58:46 | 显示全部楼层
zonda 发表于 2018-7-4 22:52
或者是分成两步来看,第一步就是:

经过第一步后,string2就是大写字母了,然后 利用 str(string2),输 ...

恩恩,有道理,理解的很透彻啊,
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-7-5 09:34:39 | 显示全部楼层
xue11 发表于 2018-7-4 23:58
恩恩,有道理,理解的很透彻啊,

我也是 刚开始学,还有很多不明白。一起交流学习嘛
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-8-9 12:42:41 | 显示全部楼层
楼主,我想问一下,小甲鱼老师在输入a=CapStr('i love FishC.com')后,再输入a,为啥就能把变化后的全部大写给打印出来呀,参数传递是怎么传递的呀
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-3-29 17:56

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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