1 定义
魔术方法就是一个类/对象中的方法,和普通方法唯一的不同是: 普通方法需要主动调用!而魔术方法是在特定时刻自动触发。
2 常用魔术方法
1.__init__(self): 初始化魔术方法, 用于初始化对象的属性
触发时机:初始化对象时触发
2.__new__(cls): 实例化魔术方法, 实例化对象, 必须返回一个对象实例
触发时机:在实例化对时触发
实例化一个对象时: 首先会触发__new__, 然后才会触发__init__
使用这个魔术方法典型应用就是单例模式, 小例子:
代码语言:javascript复制# -*- coding: utf-8 -*-
# @Author: Mehaei
# @Date: 2023-08-05 18:01:36
# @Last Modified by: Mehaei
# @Last Modified time: 2023-08-05 18:17:37
class Home(object):
instance = None
"""docstring for Home"""
def __init__(self, *arg):
super(Home, self).__init__()
self.arg = arg
print("调用__init__")
def __new__(cls):
print("调用__new__")
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
home = Home()
print(id(home))
home = Home()
print(id(home))
# 正常实例化两次对象
# 输出
'''
调用__init__
4530165240
调用__init__
4530558512
[Finished in 0.1s]
'''
# 单例模式输出
'''
调用__new__
调用__init__
4305778224
调用__new__
调用__init__
4305778224
'''
3.__del__(self): 删除对象魔术方法
触发时机:当对象没有用(没有任何变量引用)的时候被触发
注意:手动使用del删除一个对象时不一定会触发当前方法,
只有当前对象没有任何变量接收使用时才会触发
4.__call__(self): 调用对象的魔术方法
触发时机:将对象当作函数调用时触发 实例化对象()
5.__len__(self): 查看对象的长度(一般用于迭代器), 必须返回一个整型
触发时机: 使用len(对象) 的时候触发
6.__str__(self): 查看对象信息, 必须返回字符串
触发时机: 使用print(对象)或者str(对象)的时候触发
7.__repr__(self): 查看对象信息, 必须返回字符串
触发时机: 在使用repr(对象)的时候触发
8.__bool__(self): 对象转为布尔值, 必须返回布尔值
触发时机: 使用bool(对象)的时候触发
9.__format__(self, ftype): 格式化对象, 必须返回字符串
触发时机:使用字符串.format(对象)时候触发
10.__getattr__(self, attr): 获取对象成员
触发时机:获取不存在的对象成员时触发
11.__setattr__(self, attr, value): 设置对象成员
触发时机:设置对象成员值的时候触发
12.__delattr__(self, attr): 删除对象成员
触发时机:删除对象成员时触发
下面是使用的小例子:
代码语言:javascript复制# -*- coding: utf-8 -*-
# @Author: Mehaei
# @Date: 2023-08-05 18:01:36
# @Last Modified by: Mehaei
# @Last Modified time: 2023-08-05 20:46:49
class Home(object):
instance = None
"""docstring for Home"""
def __init__(self, *arg):
super(Home, self).__init__()
self.arg = arg
print("调用__init__")
def __new__(cls):
print("调用__new__")
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
def __del__(self):
print("调用__del__")
def __call__(self):
print("调用__call__")
# 默认返回None, 可以自定义返回内容
return int
def __len__(self):
print("调用__len__")
return 10
def __str__(self):
print("调用__str__")
return 'this is home'
def __repr__(self):
print("调用__repr__")
return 'this is home repr'
def __getattr__(self, attr):
print(f"调用__getattr__ {attr}")
def __setattr__(self, attr, value):
print(f"调用__setattr__{attr}:{value}")
def __delattr__(self, attr):
print(f"调用__delattr__ {attr}")
# 实例化对象时, 首先调用__new__, 然后调用__init__
home = Home()
'''
输出:
调用__new__
调用__init__
'''
# # 对象没有被任何地方使用时, 调用__del__
# del home
'''
输出:
调用__del__
'''
# # 把实例化对象当函数调用时触发
# home = Home()() # 输出: <class 'int'>
# print(home)
# print(len(home))
'''
输出:
调用__len__
10
'''
# print(home)
# """
# 调用__str__
# this is home
# """
# str(home)
# """
# 调用__str__
# """
# repr(home)
# """
# 调用__repr__
# """
# print(repr(home))
# """
# 调用__repr__
# this is home repr
# """
# home.a
# # 调用__getattr__ a
# home.a = 1
# # 调用__setattr__a:1
# del home.a
# # 调用__delattr__ a
# 在最后没有任何地方使用的时候, 也会调用del
'''
调用__del__
'''
3 上下文管理魔术方法
__enter__(self): with代码块初始化操作
1. 定义当使用 with 语句时的初始化行为
2. enter 的返回值被 with 语句的目标或者 as 后的名字绑定
__exit__(self, exctype, excvalue, traceback): with代码块结束后的操作
1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么
2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作
读写文件时, 使用的 with open() as f:f.read() 就使用这两个魔术方法
小例子:
代码语言:javascript复制# -*- coding: utf-8 -*-
# @Author: Mehaei
# @Date: 2023-08-05 18:01:36
# @Last Modified by: Mehaei
# @Last Modified time: 2023-08-05 20:28:23
class FileOpt(object):
def __init__(self, fname):
self.fname = fname
self.fp = open(fname, "r ")
def __enter__(self):
print("调用__enter__")
return self.fp
def __exit__(self, exctype, excvalue, traceback):
print("调用__exit__", exctype, excvalue, traceback)
self.fp.close()
with FileOpt("mq_learn.py") as fp:
print(len(fp.read()))
# 输出
'''
调用__enter__
165
调用__exit__ None None None
'''
4 这篇结束了!
还有一些描述符, 运算, 类型转换, 容器相关的魔术方法,这里就不一一介绍了, 因为实在太多了, 后面用到了再介绍,在实际开发中, __init__是使用频率最多的, 其次是__new__,掌握这俩个魔术方法, 在开发中基本就不会有问题了