python类的常用魔术方法

2023-09-05 14:19:57 浏览数 (1)

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__,掌握这俩个魔术方法, 在开发中基本就不会有问题了

0 人点赞