?? 前言
博客地址:
- CSDN:https://blog.csdn.net/powerbiubiu
?? 简介
在Python的类中,以两个下划线开始和结束的方法如__init__、__del__、__str__等称为魔术方法,它们常常被视为一种私有方法,不能通过类及其子类的实例调用。
魔术方法与普通方法的区别是不需要调用,需要触发。在类或对象的某些事件触发后会自动执行,如果希望根据自己的程序定制特殊功能的类,那么就需要对魔术方法进行重写。魔术方法众多,下面介绍一些常用的魔术方法。
?? 正文
1 构造与初始化
构造方法
- 触发时机: 实例化对象时自动触发(在__init__之前触发)
- 参数:至少一个cls 接收当前类,其他参数根据初始化方法参数决定
- 返回值:必须返回一个对象实例,没有返回值,则实例化对象的结果为None
- 作用:实例化对象
- 注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。
1.1 new
class Test: def __new__(cls, *args, **kwargs): obj = object.__new__(cls) print('__new__()方法被调用') print(obj) return obj def __init__(self): print('__init__()方法被调用') print(self) t = Test() # __new__()方法被调用 # <__main__.Test object at 0x0000026C2B2731D0> # __init__()方法被调用 # <__main__.Test object at 0x0000026C2B2731D0>
备注:在
1.2 init
初始化方法
- 触发机制:实例化对象之后立即触发
- 参数:至少有一个self,接收当前对象,其他参数根据需要进行定义
- 返回值:无
- 作用:初始化对象的成员
class Person: def __init__(self, name, age): self.name = name self.age = age print(f'我叫{self.name},今年{self.age}岁了') p = Person('张三', 18) # 我叫张三,今年18岁了
1.3 del
析构函数
- 触发时机:当该类对象被销毁时,自动触发
- 参数:一个self,接受当前对象
- 返回值:无
- 作用:关闭或释放对象创建时资源
- 注意:del不一定会触发当前方法,只有当前对象没有任何变量引用时才会触发
class Test: def __init__(self): print('对象初始化') def __del__(self): print('对象被销毁') t = Test() # 对象初始化 # 对象被销毁
2 可调用对象
2.1 call
可调用对象魔术方法
- 触发时机:将对象当作函数调用时触发,方式: 对象()
- 参数:至少一个self接收对象,其余根据调用时参数决定
- 返回值:根据情况而定
- 作用:可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用
class Test: def __call__(self, *args, **kwargs): print('__call__方法被调用了') t = Test() t() # __call__方法被调用了
3 类的表示
3.1 str
需要对象转换为string时,python都会默认调用该魔法方法,如print的时候,与字符串进行+运算的时候,凡是需要进行隐示类型转换为字符串的地方,都会自动调用该方法。
class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f'我叫{self.name},今年{self.age}岁了' p = Person('Tom', 18) print(p) # 我叫张三,今年18岁了
3.2 repr
函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式,某对象没有适于人阅读的解释形式的话,str() 会返回与repr(),所以print展示的都是str的格式。
class Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f'Person[name:{self.name}, age:{self.age}]' p = Person('Tom', 18) print(p) # Person[name:Tom, age:18]
3.3 同时使用__str__和__repr__
class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f'我叫{self.name},今年{self.age}岁了' def __repr__(self): return f'Person[name:{self.name}, age:{self.age}]' p = Person('Tom', 18) print(str(p)) print(repr(p)) # 我叫Tom,今年18岁了 # Person[name:Tom, age:18]
3.4 bool
- 触发时机: 使用bool(对象)的时候触发
- 参数:一个self接收对象
- 返回值:必须是布尔值
- 作用:根据实际情况决定,可以作为快捷方式使用
- 注意:仅适合于返回布尔值的操作
class Test: def __init__(self, age): self.age = age def __bool__(self): print() return self.age >= 18 # 恒等于True # return True # 恒等于False # return False t = Test(18) print(bool(t))
4 属性访问
4.1 getattr
定义当用户试图获取一个不存在的属性时的行为。
- 触发时机:获取不存在的对象成员时触发
- 参数:一个是接收当前对象的self,一个是获取成员名称的字符串
- 返回值:必须有值
- 作用:为访问不存在的属性设置值
- 注意:getattribute无论何时都会在getattr之前触发,触发了getattribute就不会在触发getattr了
4.2 getattribute
定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)
- 触发时机:使用对象成员时触发,无论成员是否存在
- 参数:1个接收当前对象self,一个是获取的成员的名称字符串
- 返回值:必须有
- 作用:在具有封装操作(私有化时),为程序开部分访问权限使用
4.3 setattr
定义当一个属性被设置时的行为
- 触发时机:设置对象成员值的时候触发
- 参数:1个当前对象的self,一个是要设置的成员名称字符串,一个是要设置的值
- 返回值:无 过程操作
- 作用:接管设置操作,可以在设置前之前进行判断验证等行为
- 注意:在当前方法中无法使用成员=值的方式直接设置成员,否则会无限递归,必须借助object的设置方法来完成
4.4 delattr
定义当一个属性被删除时的行为
- 触发时机:删除对象成员时触发
- 参数:一个当前对象的self
- 返回值:无
- 作用:可以在删除成员时进行验证。
class Test: def __getattribute__(self, item): print('__getattribute__') return super().__getattribute__(item) def __getattr__(self, item): print('__getattr__') def __setattr__(self, key, value): print('__setattr__') super().__setattr__(key, value) def __delattr__(self, item): print('__delattr__') super().__delattr__(item) t = Test() t.x # __getattribute__ # __getattr__ t.x = 1 # __setattr__ del t.x # __delattr__
5 运算符魔术方法
__add__(self,other) :实例之间的加法运算+__sub__(self,other) :实例之间的减法运算-__mul__(self,other) :实例之间的乘法运算*__truediv__(self,other) :类与类之间的真除。只有from future import division之后它才有效/__floordiv__(self,other) :类与类之间的浮点除法运算//__mod__(self,other) :类与类之间的取余运算%__pow__(self,other[,module])) :类与类之间的指数运算**__and__(self,other) :类与类之间的按位与运算&__xor__(self,other) :类与类之间的按位异或运算^__or__(self,other) :类与类之间的按位或运算|__lt__(self,other) :定义了比较操作符<__gt__(self,other) :定义了比较操作符>__le__(self,other) :定义了比较操作符<=__eq__(self,other) :定义了比较操作符==__ne__(self,other) :定义了比较操作符!=__setitem__(self, key, value) :使用self[nkey] = value赋值容器中的一项__delitem__(self, key) :删除self[nkey]
5.1 加减乘除
class Point: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __sub__(self, other): return Point(self.x - other.x, self.y - other.y) def __mul__(self, scalar): return Point(self.x * scalar, self.y * scalar) def __truediv__(self, scalar): return Point(self.x / scalar, self.y / scalar) def __eq__(self, other): return self.x == other.x and self.y == other.y p1 = Point(1, 2) p2 = Point(3, 4) # 加法操作 p3 = p1 + p2 print(p3.x, p3.y) # 输出: 4, 6 # 减法操作 p4 = p1 - p2 print(p4.x, p4.y) # 输出: -2, -2 # 乘法操作 p5 = p1 * 2 print(p5.x, p5.y) # 输出: 2, 4 # 除法操作 p6 = p1 / 2 print(p6.x, p6.y) # 输出: 0.5, 1.0 # 等值比较操作 print(p1 == p2) # 输出: False print(p1 == Point(1, 2)) # 输出: True
5.2 比较运算
class Person: def __init__(self, name, age): self.name = name self.age = age def __lt__(self, other): return self.age < other.age def __eq__(self, other): return self.age == other.age p1 = Person("Alice", 25) p2 = Person("Bob", 30) p3 = Person("Charlie", 25) print(p1 < p2) # 输出: True print(p1 == p3) # 输出: True
6 赋值运算符魔术方法
iadd(self, other) :定义赋值加法的行为:+=isub(self, other) :定义赋值减法的行为:-=imul(self, other) :定义赋值乘法的行为:*=itruediv(self, other) :定义赋值真除法的行为:/=ifloordiv(self, other) :定义赋值整数除法的行为://=imod(self, other) :定义赋值取模算法的行为:%=ipow(self, other[, modulo]) :定义赋值幂运算的行为:**=ilshift(self, other) :定义赋值按位左移位的行为:<<=irshift(self, other) :定义赋值按位右移位的行为:>>=iand(self, other) :定义赋值按位与操作的行为:&=ior(self, other) :定义赋值按位或操作的行为:|=ixor(self, other) :定义赋值按位异或操作的行为:^=
7 容器相关魔术方法
__len__(self) :定义当被 len() 调用时的行为(返回容器中元素的个数)__getitem__(self, key) : 定义获取容器中指定元素的行为,相当于 self[key]__setitem__(self, key, value) : 定义设置容器中指定元素的行为,相当于 self[key] = value__delitem__(self, key) :定义删除容器中指定元素的行为,相当于 del self[key]__iter__(self) :定义当迭代容器中的元素的行为__next__(self) :从iterable对象中获取下一个元素__reversed__(self) : 定义当被 reversed() 调用时的行为__contains__(self, item) : 定义当使用成员测试运算符(in 或 not in)时的行为__missing__ 字典使用__getitem__() 调用时,key不存在执行该方法
7.1 getitem__和__setitem
class MyList: def __init__(self, items): self.items = items def __getitem__(self, index): return self.items[index] def __setitem__(self, index, value): self.items[index] = value l = MyList([1, 2, 3, 4]) print(l[2]) # 3 l[2] = 5 print(l[2]) # 5
7.2 contains
class MyList: def __init__(self, items): self.items = items def __contains__(self, item): return item in self.items l = MyList([1, 2, 3, 4]) print(2 in l) # True print(5 in l) # False
7.2 iter__和__next_
迭代器
class MyIterator: def __init__(self, start, end): self.start = start self.end = end def __iter__(self): return self def __next__(self): if self.start >= self.end: raise StopIteration value = self.start self.start += 1 return value iterator = MyIterator(0, 5) for iter in iterator: print(iter) # 0 # 1 # 2 # 3 # 4
8 魔法属性
8.1 doc
获取类或对象内部文档
class MyClass(): """ 自定义一个类,这里写了一些说明 """ def __init__(self): pass print(MyClass.__doc__) # 自定义一个类,这里写了一些说明
8.2 name
获取类名或函数名
class Foo: pass class MyClass: def task(self, func): print(func.__name__) def func(): print("我是func1函数") obj = MyClass() obj.task(Foo) # Foo obj.task(func) # func
8.3 class
获取当前对象获取的类
class Foo: pass obj = Foo() print(obj.__class__) # <class '__main__.Foo'> print(obj.__class__.__name__) # Foo
8.4 base
获取一个类直接继承的所有父类,返回元组
class Foo: pass class Boo: pass class MyClass(Foo, Boo): pass print(MyClass.__bases__) # (<class '__main__.Foo'>, <class '__main__.Boo'>)
8.5 dict
获取类或对象的的内部成员结构
主要用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典
class MyClass: name = "zhangsan" age = 18 def one(self): print("one") def two(self): print("two") print(MyClass.__dict__) # {'__module__': '__main__', 'name': 'zhangsan', 'age': 18, 'one': <function MyClass.one at 0x000001D07AD54AF0>, 'two': <function MyClass.two at 0x000001D07AD54B80>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}