Python – 魔法方法和方法重写

魔法方法总结

字符串/字节序列表示相关:__repr__、__str__,__format__,__bytes__。这些主要是做一些格式化的操作。

数值转换:__abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__。

集合模拟:__len__、__getitem__、__setitem__、__delitem__、__contains__。用的列表就包括了这些方法。

迭代枚举:__iter__、__reversed__、__next__。主要用于迭代器和生成器。

可调用模拟:__call__。主要是加上括号就能触发调用。

上下文管理:__enter__、__exit__。大家还记得with读取文件吗,其实就是上下文管理器。

实例创建和销毁:__new__、__init__、__del__。这些都是创建类中常常使用的。

属性相关:__getattribute__、__getattr__、__setattr__、__delattr__、__setattr__、__dir__。这五个方法主要是用于操作属性的。

属性描述符:__get__、__set__、__del__。用来定义属性描述符。

方法重写

如果父类方法的功能不能满足需求,可以在子类重写父类的方法,实例如下:

class Parent: #定义父类 def myMethod(self): print(‘调用父类方法’) class Child(Parent): #定义子类 def myMethod(self): print(‘调用子类方法’) c=Child() #子类实例c.myMethod() #子类调用重写方法super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法#super()是用于调用父类(超类)的一个方法。#调用子类方法#调用父类方法

魔法方法

在Python中,有一些内置好的特定的方法,这些方法在进行特定的操作时会自动被调用,称之为魔法方法,下面介绍几种常见的魔法方法。

  • __ new__(cls[,* argv])
  • __ new__ 是在一个对象实例化的时候所调用的第一个方法,它的第一个参数是这个类,其他的参数是用来直接传递给 __ init__ 方法
  • __ new__ 决定是否要使用该 __ init__ 方法,因为 __ new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __ new__ 没有返回实例对象,则 __ init__ 不会被调用
  • __ new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string
  • cls:代表一个类的名称
  • self:代表一个实例对象的名称

class myMethod(str): def __new__(cls,string): string=string.upper() return str.__new__(cls,string) X=myMethod(‘DataScience’)print(X)#DATASCIENCE

__ init__:

初始化函数,在创建实例对象为其赋值时使用,在__ new__ 之后,__ init __ 必须至少有一个参数self,就是这个 __ new__ 返回的实例,__ init__ 是在 __ new__ 的基础上可以完成一些其它初始化的动作,__ init__不需要返回值。

class Dog: def __init__(self,color,brand): self.color=color self.brand=brandpuppy=Dog(‘黑色’,’拉布拉多’)print(puppy)#

下面再来一个结合__ init__ 和__ new__两个魔法方法的例子:

class A(object): passclass B(A): def __init__(self): print(‘__init__被调用’) def __new__(cls): print(‘__new__被调用’) print(id(cls)) return object.__new__(A) #注意此处采用了参数A而不是cls,__new__没有正确返回当前类cls的实例b=B()print(b)print(type(b)) #类型所继承的基类print(id(A))print(id(B))”’__new__被调用281212608576828121260838802812126085768”’

从运行结果可以看出,__ new__ 中的参数cls和B的id是相同的,表明__ new__ 中默认的参数cls就是B类本身,而在return时,并没有正确返回当前类cls的实例,而是返回了其父类A的实例,因此__ init__这一魔法方法并没有被调用,此时__ new__虽然是写在B类中的,但其创建并返回的是一个A类的实例对象。

现在将return中的参数A变为cls,再来看一下运行结果:

class A(object): passclass B(A): def __init__(self): print(‘__init__被调用’) def __new__(cls): print(‘__new__被调用’) print(id(cls)) return object.__new__(cls) #注意此处采用了参数A而不是cls,__new__没有正确返回当前类cls的实例b=B()print(b)print(type(b)) #类型所继承的基类print(id(A))print(id(B))”’__new__被调用2812126087656__init__被调用28121260867122812126087656”’

可以看出,当__ new__ 正确返回其当前类cls的实例对象时,__ init__被调用了,此时创建并返回的是一个B类的实例对象。

__ class__:

获得已知对象的类 ( 对象.__ class__)。

基础格式如下:

class My: passa=A()print(a.__class__)#

__ class__在下面这种情况中是有用的:即当一个类中的某个成员变量是所有该类的对象的公共变量时.

下面看一个例子:

class My: count=0 def addcount(self): self.__class__.count +=1 a=My()a.addcount()print(a.count)print(‘*’*50)b=My()b.addcount()print(b.count)#1#**************************************************#2

从运行结果可以看出,虽然a和b是两个不同的My类的实例对象,但采用了__ class__ 之后,分别调用两个对象的addcount方法之后,获取到的对象的count属性却是在不断累加的,此时self.__ class__ .count不再是单纯的某个对象私有的属性,而是类的所有实例对象的共有属性,它相当于self.A.count。若将self.__ class__ .count += 1变为self.count += 1,此时__ class__的效果就十分明显了。

class My: count=0 def addcount(self): self.count +=1 a=My()a.addcount()print(a.count)print(‘*’*50)b=My()b.addcount()print(b.count)#1#**************************************************#1

__ str__:

在将对象转换成字符串 str(对象) 测试的时候,打印对象的信息,__ str__ 方法必须要return一个字符串类型的返回值,作为对实例对象的字符串描述,__ str__ 实际上是被print函数默认调用的,当要print(实例对象)时,默认调用__ str__ 方法,将其字符串描述返回。如果不是要用str()函数转换。当打印一个类的时候,那么print首先调用的就是类里面的定义的__ str__。

class My(): def __init__(self,name): self.name=name def __str__(self): return(‘我是My类的实例对象my,我的名字叫%s’%self.name) my=My(‘小王’)print(My)print(my)##我是My类的实例对象my,我的名字叫小王

类的专有方法

  • __ init__ : 构造函数,在生成对象时调用
  • __ del__ : 析构函数,释放对象时使用
  • __ repr__ : 打印,转换
  • __ setitem__ : 按照索引赋值
  • __ getitem__: 按照索引获取值
  • __ len__ : 获得长度
  • __ cmp__ : 比较运算
  • __ call__ : 函数调用
  • __ add__ : 加运算
  • __ sub__ : 减运算
  • __ mul__ : 乘运算
  • __ truep__ : 除运算
  • __ mod__ : 求余运算
  • __ pow__ : 乘方

总结

  • 修改类方法和属性,会影响实例方法和属性
  • 一个实例属性的修改,不会影响另一个实例属性
  • 类方法可以修改,但实例方法不允许修改
郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
(0)
用户投稿
上一篇 2022年8月20日
下一篇 2022年8月20日

相关推荐

  • 陈萌大胆示爱朱小伟,大衣哥亲自出门迎接,满脸笑容藏不住

    作为草根明星,大衣哥火了之后,带动着自己的家人都火了,而他的“流量”也给全村人带来了福利。但是大火之后,一些弊端就随之而来,比如大衣哥儿子朱小伟的婚姻。 朱小伟跟陈亚男结婚的时候,…

    2022年8月23日
  • 同事都有对象单身女服务员趴桌大哭 只想找个厨师

    现如今,很多女生对另一半的要求很高,不仅要有房有车,还有存款以及几十万的彩礼等。同事都有对象单身女服务员趴桌大哭,网友纷纷质疑她是不是要求太高的原因,所以一直没有脱单,具体详情跟小…

    2022年10月15日
  • 谈谈FC中的Return和Output的区别

    FC来自于英文单词Function的缩写,意为函数。和C/PASCAL语言一样,FC同样也支持返回值(Return)和输出参数(Output)。既然他们都可以从函数获取结果,那我们…

    2022年6月15日
  • 无论炖什么鱼,不能放这“2种”料!否则鱼又腥又难吃,还没营养

    导读:前段时候,有粉丝听说我钓鱼很牛,所以不少当地的粉丝,就隔三差五地邀请我去钓鱼,所以在前天,我和3位粉丝、2位朋友来到我们河边,比赛钓鱼!可别说,当天我的运气真的是爆棚了,一下…

    2022年8月31日
  • 用细胞夹夹黑头,简直不要太快乐

    让我看看有哪位姐妹还是在用手挤黑头的!手上那么多细菌,黑头也只会越挤越多!一定要试试细胞夹,一整个夹出来要多爽有多爽 我是个大油皮,本身t字区就喜欢出油,黑头自然也很多,跟着骆大娘…

    2022年6月17日
  • 英雄联盟手游在哪里搜索好友?英雄联盟手游搜索好友方法介绍

    英雄联盟手游在哪里搜索好友?好友太多的时候想要找到某一个人就会比较难,今天我们来了解一下搜索好友的方法,小编这就在下面的攻略中为大家介绍,有兴趣了解搜索好友方法的都可以来看看下面的…

    2022年10月26日
  • 梭子蟹怎么保存才新鲜(2种梭子蟹保存实用方法)

    螃蟹和梭子蟹的保存方法自然也不同。新鲜的大闸蟹吃不完,可以捆好脚手放入冰箱保鲜室直接保存,几天都新鲜。而如果是梭子蟹,则不适用于这个方法。新鲜的梭子蟹放入冰箱直接冷冻,很容易导致蟹…

    2022年5月7日
  • 技术干货 -postman接口测试获取HTTP请求

    如果你正在使用API构建客户端应用程序—移动应用程序、网站或桌面应用程序—你可能希望看到在应用程序中发送和接收的实际HTTP请求流量。在某些情况下,可能会发现甚至没有文档记录的AP…

    2022年6月14日
  • 魂师对决:聊聊新增6钻转运铃购买上限和新魂环属性调整的事

    大家好,我是正在实事求是的何二维一。 想必大部分玩家也都知道,昨天早上在周年商城上架了全新的兑换货币转运铃和相关的资源之后,很多朋友亦是兴致勃勃的去兑换了其中的新凶兽系魂环【天音幻…

    2022年8月5日
  • 我们一定要会写的三种代理模式

    代理模式是一种设计模式,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展。 目标:在eat方法执行的前后增加业务逻辑 准备工作 先准备三个基础类 public interf…

    2022年7月4日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息