🍀 前言
博客地址:
👋 简介
在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>
备注:在__new__
方法中,需要return语句,否则程序不会继续往下执行初始化函数__ini__
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}