Python3中的魔术方法汇总

Python魔术方法详解:构建自定义对象行为
本文深入探讨了Python中的魔术方法,包括构造、属性访问、表示和描述、运算符重载等方面,展示了如何通过魔术方法定制类的行为,增强面向对象编程能力。通过实例演示了如何使用魔术方法实现对象的初始化、属性读写、比较运算、类型转换等操作,以及上下文管理、序列化和复制等高级特性。
该文章已生成可运行项目,

欢迎访问个人网络日志网站,获取最新文章!
(二)Python中的魔术方法

1.魔术方法简介

Python 中的魔术方法(Magic)方法,是那些被__包围的方法,在对象继承时,子类可以重写父类的魔术方法以实现定制功能,用于增强Python面向对象编程的能力。魔术方法在创建对象或对象操作时自动调用,不需要显式使用。譬如当我们判断对象是否相等时只使用了==符号,并未显式调用__eq__方法,但却实现了判断两个实例是否相等的功能,犹如变魔法一般。魔术方法按功能可分为如下几类,

  • 1.构造、初始化和析构对象
  • 2.控制属性读写
  • 3.对象的表示和描述,如__str__
  • 4.在定制类对象间支持使用运算符号,如+,-,*,/,//,==,<=
  • 5.定义个性化序列
  • 6.反射
  • 7.可调用对象
  • 8.上下文管理
  • 9.描述器
  • 10.复制
  • 11.使对象支持pickle序列化反序列化

因不同的PEP(Python Enhancement Proposal)会不断添加删除魔术方法,故本文具有一定时效性。本文中涉及的魔术方法列表:

序号 方法 序号 方法
1 __init__ 42 __radd__
2 __new__ 43 __iadd__
3 __del__ 44 __int__
4 __getattr__ 45 __float__
5 __getattribute__ 46 __oct__
6 __setattr__ 47 __hex__
7 __delattr__ 48 __index__
8 __str__ 49 __complex__
9 __repr__ 50 __len__
10 __format__ 51 __getitem__
11 __hash__ 52 __setitem__
12 __bool__ 53 __delitem__
13 __dir__ 54 __iter__
14 __sizeof__ 55 __reversed__
15 __eq__ 56 __contains__
16 __ne__ 57 __missing__
17 __le__ 58 __instancecheck__
18 __ge__ 59 __subclasscheck__
19 __lt__ 60 __call__
20 __gt__ 61 __enter__
21 __pos__ 62 __exit__
22 __neg__ 63 __get__
23 __invert__ 64 __set__
24 __round__ 65 __delete__
25 __floor__ 66 __copy__
26 __ceil__ 67 __deepcopy__
27 __trunc__ 68 __getstate__
28 __add__ 69 __setstate__
29 __sub__ 70 __slots__
30 __mul__
31 __matmul__
32 __truediv__
33 __floordiv__
34 __mod__
35 __divmod__
36 __pow__
37 __lshift__
38 __rshift__
39 __and__
40 __or__
41 __xor__

2.不同类型的魔术方法

2.1 用于对象构造析构的魔术方法

  • __init__:在定义class时使用最多的方法,用于初始化对象, 在创建对象时自动调用。
  • __new__:初始化对象时,在__init__之前调用的方法,该方法实现对象的构造,返回对象实例给__init__中的self
  • __del____del__方法是定义类的析构函数,其并不是为了定义del Object时对象的行为,而是为了在对象被垃圾回收时执行特定的操作,如关闭socket,文件描述符等。因为当Python解释器退出时,对象有可能依然未被释放,因此__del__中定义册操作不一定能被执行,故在实际中应避免使用__del__

    示例:
class World:
    def __new__(cls, *args, **kargs):
        print("__new__ method called.")
        inst = super(World, cls).__new__(cls)
        return inst
    def __init__(self, countries):
        print("__init__ method called.")
        self.countrie = countries
    def __del__(self):
        print("Your World Is Cleaned Up.")

w = World(1)
o = World(2)
del o
"""
Output:
# __new__ method called.
# __init__ method called.
# __new__ method called.
# __init__ method called.
# Your World Is Cleaned Up.
"""

2.2 用于控制属性读写的魔术方法

  • __getattr__:拦截通过obj.key获取对象不存在的key属性时调用的方法,注意与__getattribute__方法的区别,可实现懒加载,在调用属性时再去操作耗时的动作,如文件读取等。
  • __getattribute__:拦截所有的属性访问,注意避免在此方法中使用self.key,以免造成死循环
  • __setattr__:拦截所有属性的赋值操作,注意避免在此方法中通过self.key=value的方式给实例赋值,以免造成死循环。
  • __delattr__:拦截所有属性的清除操作,注意避免在此方法中通过del self.key的方式清除实例属性,以免造成死循环。


    示例:
class World:
    def __init__(self, countries):
        self.countries = countries
    
    def __getattr__(self, key):
        print(f"__getattr__ called: unexisted key {
     
     key}")
        return None
    
    def __getattribute__(self, key):
        print(f"__getattribute__ called: key {
     
     key}")
        return super(World, self).__getattribute__(key)

    def __setattr__(self, key, value):
        if key in self.__dict__:
            print(f"__setattr__ called: key existed {
     
     key}")
        else:
            print(f"__setattr__ called: key unexisted {
     
     key}")
        self.__dict__[key] = value
    
    def __delattr__(self, key):
        print(f"__delattr__ called: key {
     
     key}")
        del self.__dict__[key]

w = World(256)
w.oceans = 5
del w.countries
"""
Output:
# __getattribute__ called: key __dict__
#__setattr__ called: key unexisted countries
# __getattribute__ called: key __dict__

# __getattribute__ called: key __dict__
# __setattr__ called: key unexisted oceans
# __getattribute__ called: key __dict__

# __delattr__ called: key countries
# __getattribute__ called: key __dict__
"""

2.3 对象的表示和描述

  • __str__:使得可通过str()方法获取对象的可读信息,__str__输出的应该是用户关注的容易理解的信息,因此对那些负责与客户交互的类,至少更应该重写__str__方法。

  • __repr__:使得可通过repr()方法获取对象的详细信息,包括存储地址等,__str__中的信息是__repr__中的一部分。stackoverflow上有个回答。1__str__是面向普通用户的信息,__repr__是面向开发者的信息,倒也形象。如果开发者要输出开发人员足够知悉的属性,就需要重写该方法。
    重写__repr__方法注意:__repr__方法是实例方法,因此带一个参数self,也只能带这个参数;
    输出的信息尽可能满足开发者的要求,信息必须详尽和准确。

  • __format__:定义通过"prefix {:code}".format(obj)时实例输出的形式,code__format__的参数,用来确定以哪种格式format,定制数值或字符串类型时常希望重写此方法

  • __hash__:定义hash对象实例的返回值,需要为1个整数,默认的hash方法根据对象的地址和属性值算出来int类型整数为对象的hash值。一个对象在其生命周期内,如果保持不变,就是hashable(可哈希的)。像int,string是可哈希的,dict,list等是不可哈希的。哈希性使得对象可以用作dictionary键和set成员,因为这些数据结构在内部使用了哈希值。如果要判断 item in setTrue,则item==set中的一个元素hash(item)==hash(set中的一个元素)

  • __bool__:调用bool()方法时对象的返回值,需为True/False

  • __dir__:调用dir()方法时对象的返回值,一般不需要重写该方法,但在定义__getattr__时有可能需要重写,以打印动态添加的属性。

  • __sizeof__:定义sys.getsizeof() 方法调用时的返回,指类的实例的大小,单位是字节,在使用C扩展编写Python类时比较有用。

    示例:

formats = {
   
   
    "long":"Country Has {c.provinces} Provinces",
    "short":"C H {c.provinces} P",
}
class Country:
    def __init__(self, provinces, name):
        self.provinces = provinces
        self.name = name
    def __str__(self):
        return f"Country has {
     
     self.provinces} provinces"
    def __repr__(self):
        s="In __repr__:\n<{} object at {:#016x}>\n".format(repr(self.__class__),id(self) )
        s+=super().__repr__()
        s+="\n"
        s+=repr(self.__dict__)
        return s
    def __format__(self, code):
        return formats[code].format(c=self)
    
    def __eq__(self, obj):
        return self.provinces == obj.provinces
    
    def __hash__(self):
        return 12
        #return hash(self.name)
    def __bool__(self):
        print(self.name)
        return self.name == "Hunan"
    def __dir__(self):
        l = list(self.__dict__.keys())
        l.append("GDP")
        return l
    def __sizeof__(self):
        print("__sizeof__ called")
        return len(self.__dict__)
c = Country(264, "Hunan")
d = Country(264, "Henan")
print(hash(c))
print(hash(d))
print(c == d)
s = set()
s.add(c)
print(d in s)
本文章已经生成可运行项目
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值