在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 init ,Python中所有的魔术方法均在官方文档中有相应描述,但是对于官方的描述比较混乱而且组织比较松散。很难找到有一个例子。

构造和初始化

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

from os.path import join
class FileObject: '''给文件对象进行包装从而确认在删除时文件流关闭'''def __init__(self, filepath='~', filename='sample.txt'): #读写模式打开一个文件 self.file = open(join(filepath, filename), 'r+') def __del__(self): self.file.close() del self.file

2、new:很多人认为__init__是类的构造函数,其实不太确切,__init__更多的是负责初始化操作,相当于一个项目中的配置文件,__new__才是真正的构造函数,创建并返回一个实例对象,如果__new__只调用了一次,就会得到一个对象。继承自object的新式类才有__new__这一魔法方法,__new__至少必须要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供,__new__必须要有返回值,返回实例化出来的实例(很重要),这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例,若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行。__new__是唯一在实例创建之前执行的方法,一般用在定义元类时使用。
创建对象的步骤:
a、首先调用__new__得到一个对象
b、调用__init__为对象添加属性
c、将对象赋值给变量
下面来看一个结合__init__和__new__两个魔法方法的例子:

class A(object):pass
class B(A):def __init__(self):print("这是__init__方法")def __new__(cls, *args, **kwargs):print("这是__new__方法")print(id(cls))return object.__new__(cls)b =B()
#这是__new__方法
#1855412042008
#这是__init__方法
print(b)
#<__main__.B object at 0x0000020ED3A1A358>
print(type(b))
#<class '__main__.B'>
print((id(A)))
#1855412031624
print(id(B))
#1855412042008

从运行结果看,new__中参数cls和B的id相同,表明__new 中默认的参数cls就是B类本身,同时在return时返回了B类的实例,在创建完实例之后还需调用__init__函数,

class A(object):pass
class B(A):def __init__(self):print("这是__init__方法")def __new__(cls, *args, **kwargs):print("这是__new__方法")print(id(cls))return object.__new__(A)b =B()
#这是__new__方法
#2250047313256
print(b)
#<__main__.B object at 0x0000020ED3A1A358>
print(type(b))
#<class '__main__.A'>
print((id(A)))
#2250047298152
print(id(B))
#2250047313256

我们发现__init__函数没有被调用,因为__new__返回是A的实例对象。

__del__

del:对象在程序运行结束之后进行垃圾回收的时候调用这个方法,来释放资源。此时,此方法是被自动调用的。除非有特殊要求,一般不要重写。在关闭数据库连接对象的时候,可以在这里,释放资源。

class NewClass(object):num_count = 0  # 所有实例共享此变量,即不单独为每个实例分配def __init__(self,string):self.string = stringNewClass.num_count += 1print(self.string +"  " , NewClass.num_count)def __del__(self):NewClass.num_count -= 1print("del" + self.string , NewClass.num_count)def test(self):print("aa")aa = NewClass("Hello")
bb = NewClass("World")
cc = NewClass("aaaa")
print("Over")Hello   1
World   2
aaaa   3
Over
delHello 2
delWorld 1
delaaaa 0

可以看出在程序运行结束之后,__del__默认被调用了三次,分别对实例对象aa,bb,cc进行垃圾回收,因为此时创建的实例已经没有对象再指向它了。下面再看一个例子:

class NewClass(object):def __init__(self,string):self.string = stringprint(self.string +"__init__方法被调用" )def __del__(self):print("del" + self.string )def test(self):print("aa")aa = NewClass("Hello")
bb = aa
del aa
del bb
print("Over")Hello__init__方法被调用
delHello
Over

可以看出,aa和bb指向的是同一个实例对象,在del aa的时候,__del__并没有被调用,因为此时这个对象还在被bb引用着,当del bb的时候,__del__就默认被调用了,因为此时没有变量再引用这个实例对象了,相当于其引用计数变为0了,这个对象理所当然就会被垃圾回收。

总而言之,__del__魔法方法是在对象没有变量再引用,其引用计数减为0,进行垃圾回收的时候自动调用的。

__calss__

class:获得已知对象的类 ( 对象.class)。

class A():count = 0def add(self):self.__class__.count += 1print(self.__class__.count)
a =A()
a.add()
b=A()
b.add()
c=A()
c.add()结果:
1
2
3

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

__str__

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

class C:def __init__(self,name):self.name  =  namedef __str__(self):return "C的实例对象"+self.name
a = C("ok")
print(C)
print(a)
结果:
<class '__main__.C'>
C的实例对象ok

__repr__

repr:如果说__str__体现的是一种可读性,是给用户看的,那么__repr__方法体现的则是一种准确性,是给开发人员看的,它对应的是repr()函数,重构__repr__方法后,在控制台直接敲出实例对象的名称,就可以按照__repr__中return的值显示了。

>>> class C:
...     def __init__(self,name):
...         self.name  =  name
...     def __str__(self):
...         return "C的实例对象"+self.name
...     def __repr__(self):
...         return "C的信息"+self.name
...
>>> a = C("ok")
>>> print(a)
C的实例对象ok
>>> a
C的信息ok

简单的定制

import  time as t
class MyTime():# 开始计时def __init__(self):self.promt ='未开始运行'def __str__(self):return self.promtdef start(self):self.start = t.localtime()print("计时开始")# 停止时间def stop(self):self.stop = t.localtime()print("计时结束")self._clac()def _clac(self):  # 定义私有方法self.lasted = []self.promt = "总共运行的时间"for i in range(6):self.lasted.append(self.stop[i] - self.start[i])self.promt += str(self.lasted[i])print(self.promt)def __add__(self, other):promt = "总共运行了"result = []for i in range(6):result.append(self.lasted[i] + other.lasted[i])if result[i]:promt += (str(result[i]))return  promta = MyTime()
print(a.promt)
a.start()
t.sleep(3)
a.stop()

结果:

未开始运行
计时开始
计时结束
总共运行的时间000003

__base__

bases:获取指定类的所有父类构成元素,使用方法为类名.bases

class A():pass
class B(A):pass
class C():pass
class D(B,C):pass
print(D.__bases__)
结果:
(<class '__main__.B'>, <class '__main__.C'>)

__mro__

显示指定类的所有继承脉络和继承顺序,假如这个指定的类不具有某些方法和属性,但与其有血统关系的类中具有这些属性和方法,则在访问这个类本身不具有的这些方法和属性时,会按照__mro__显示出来的顺序一层一层向后查找,直到找到为止。

class A():pass
class B(A):pass
class C():pass
class D(B,C):pass
print(D.__mro__)结果:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>)

__call__

call:具有__call__魔法方法的对象可以使用XXX()的形式被调用,比如说类的实例对象

class Dog(object):def __init__(self):print('__init__被调用')def __call__(self, *args, **kwargs):print("__call_方法被调用")
lao = Dog()
lao()
结果:
__init__被调用
__call_方法被调用

属性访问

__getattribute__

getattribute:属性访问拦截器,在访问实例属性时自动调用。在python中,类的属性和方法都理解为属性,且均可以通过__getattribute__获取。当获取属性时,相当于对属性进行重写,直接return object.getattribute(self, *args, **kwargs)或者根据判断return所需要的重写值,如果需要获取某个方法的返回值时,则需要在函数后面加上一个()即可。如果不加的话,返回的是函数引用地址。下面看一个例子:

class Test():def __init__(self,name):self.name1 = nameself.name2 = "cpp"def __getattribute__(self, item):if item == "name1":return 'redirect python'else:return object.__getattribute__(self,item)S = Test("python")
print(S.name1)
print(S.name2)结果:
redirect python
cpp

在创建实例对象s并对其初始化的时候,subject1的值设置为‘python’,subject2的值设置为‘cpp’,在访问s的subject1属性时,因为Test类对object类中的__getattribute__方法进行了重写,所以在调用此方法时,首先对要访问的属性做一个拦截和判断,此时__getattribute__方法中的参数item对应的是要访问的属性,若要访问subject1属性,则对该属性进行重写,返回了一个不同的字符串,我们可以看到,在初始化时,subject1 的值为‘python’,而在访问subject1这个属性时,返回的值是’redirect python’,而在访问subject2时,则调用其父类中的__getattribute__方法,返回正常的subject2属性的值。当然,在访问类的方法属性时,也可以通过重写__getattribute__的方法对其进行重写。

__getattr__

定义当用户试图获取一个不存在的属性行为时
getattr 语法:
getattr(object, name[, default])
参数

  • object – 对象。
  • name – 字符串,对象属性。
  • default – 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError

__setattr__

定义当一个属性被设置时的行为

__delattr__

定义当一个属性被删除时的行为

class H:def __getattribute__(self, item):print("getattribute")return super().__getattribute__(item)def __getattr__(self, name):print("getattr")def __setattr__(self, key, value):print("setattr")super.__setattr__(key,value)def __delattr__(self, item):print("delattr")super().__delattr__(item)
>>> c = H()
>>> c.x
getattribute
getattr
>>> c.x = 1
setattr
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<stdin>", line 9, in __setattr__
TypeError:  expected 2 arguments, got 1
>>> del c.x
delattr
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<stdin>", line 12, in __delattr__
AttributeError: x

例子:

Python——魔方方法相关推荐

  1. python魔方方法__getitem__、__setitem__和__len__

    python魔方方法__getitem__.setitem__和__len 目录 python魔方方法__getitem__.__setitem__和__len__ 一.简介 二.详解 三.代码 四. ...

  2. python魔方方法__call__

    python魔方方法__call__ 目录 python魔方方法__call__ 一.简介 二.详解 三.代码 四.Reference 一.简介 当一个类,实现了__call__方法,那么这个类的实例 ...

  3. python魔方方法__add__、__mul__、__sub__、__truediv__

    python魔方方法__add__.__mul__.__sub__.__truediv__ 目录 python魔方方法`__add__.__mul__.__sub__.__truediv__` 一.简 ...

  4. Python —— 魔方方法

    在Python中 方法名为:XXX() 就是魔方方法 init() 初始化函数,用于完成默认的设置 new() 返回一个对象的实例,init() 无返回值 new()是一个类方法 del() 析构方法 ...

  5. Python 魔方方法

    class Person:# 默认打印对象,显示类名+地址# 重写该方法,打印该方法的返回值def __str__(self):return '我叫{},今年{}岁'.format(self.name ...

  6. Python魔方方法详解

    原文链接: https://fishc.com.cn/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtype ...

  7. Python基础day08【面向对象(类、对象、属性)、魔方方法(init、str、del、repr)】

    视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员]   目录 0.复习 1.类外部添加和获取对象属性 2.类内部操作属性 3.魔法方法 3.1.__i ...

  8. python之有关魔方方法的内容

    魔方方法: 在python的类中,以下划线开头,两个下划线结尾的方法,如常见的:init,str,__del__等,就被称为魔方方法,这些方法在类或对象进行特定的操作时会被自动调用,我们可以使用或重写 ...

  9. Python Day11 魔方方法

    Python种的魔方方法 Python种有许多魔方方法供我们使用 魔法方法被双下划线包围,例如__init__. 魔法方法的第一个参数应为cls(类方法) 或者self(实例方法). 下面介绍常见的魔 ...

最新文章

  1. latex 表格单元格上下左右居中_Excel文字对齐技巧:学会这6种方式,快速整理规范表格...
  2. 让我们山寨一张Windows Azure Global的壁纸
  3. TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞
  4. 多终端数据同步机制设计
  5. css中的媒体查询_CSS中的媒体查询
  6. python 进程与线程(理论部分)
  7. swift - 关于title问题
  8. 怎么自动响应richTextBox超级链接单击click事件
  9. 酒后谈IT,那些术语大妈都能秒懂!
  10. 合肥工业大学机器人技术期末_机器人技术基础期末考试复习资料
  11. Linux基本操作(实训一)
  12. UI——day3.IOS设计规范
  13. printf打印二进制数据
  14. java实现Word文件转换成PDF
  15. 人力资源管理专业知识与实务(初级)【14】
  16. storm风暴英雄 tempo_Tempostorm攻略 10tips避免不合时宜之死
  17. 不想升级,iOS系统自动更新可彻底关闭! 2016-05-23 16:38 更新/自动/on 昨天笔者发布了一篇关于iOS系统总提醒更新,到底要不要升级的文章,不少读者在微信上留言给笔者, iPhon
  18. 记录一次 在linux 搭建的mysql迁移到docker容器中
  19. 全球及中国BTK抑制剂市场发展状况与投资前景建议报告2022-2028年
  20. spring 定义自己的标签 学习

热门文章

  1. 计算机网络之ip、子网掩码、网络号、主机号等概念解析
  2. 网卡VXLAN的offload技术介绍
  3. 存储过程与函数-创建存储过程
  4. 《水经注地图服务》图层管理介绍
  5. Python面试题(三)
  6. 短视频开发SDK 架构设计实践
  7. vue未登录跳转至登录页面
  8. Keil MDK终于免费了,并且没有代码大小限制~
  9. 开源项目车牌识别EasyPR的使用
  10. 实验二 CPU 部件实现之 ALU 和寄存器堆