You'll miss 100% of shots you don't take.
一、魔术方法简介
Python 中所有以双下划线“__”包起来的方法,统称为“Magic Method”(魔术方法)。
魔术方式是 Python 的内置方法,不需要主动调用,当我们对实例调用某些特定函数或运算符时,会自动触发。例如最常见的 __new__ 和 __init__:当调用 p = Person() 时,首先触发 __new__ 创建一个 instance 并返回,然后触发 __init__ 用传入的参数对 instance 进行初始化。
Python 的魔术方法有很多,下面介绍一些常见的魔术方法。
二、常见的魔术方法及代码示例
1.实例生命周期、允许实例像函数一样被调用
__new__(cls)、__init__(self):创建实例、实例初始化的时候触发
__del__(self):销毁实例的时候触发
__call__(self):实例像函数一样被调用时触发
代码示例:
class Person(object):
def __new__(cls, name, age, city="beijing"):
print('__new__()方法,"创建实例"时触发。')
instance = super(Person, cls).__new__(cls)
# instance = object.__new__()
print(instance, id(instance))
return instance
def __init__(self, name, age, city="beijing"):
print('__init__()方法,"初始化实例"时触发。')
# __init__()的输入参数self,就是__new__()的返回值instance
print(self, id(self))
self.name = name
self.age = age
self.city = city
# 普通方法
def cook(self, menu):
print('这是一个普通函数:cook()')
print(f"{self.name}正在煮{menu}...")
def __call__(self, course):
print('__call__()方法,"实例像函数一样被调用"时触发。')
print(f"{self.name}正在自习室学习{course}...")
def __del__(self):
print('__del__()方法,"实例销毁"时触发。')
# 先触发__new__()创建一个instance,然后自动调用__init__()对实例进行初始化
p = Person('Tom', 16, city='shanghai')
print("----------")
p.cook('coffee') # 调用普通函数
print("----------")
p('Maths') # 允许实例像函数一样被调用,触发__call__()方法
print("----------")
del p # 实例被销毁,触发__del__()方法
运行结果:
__new__()方法,"创建实例"时触发。
<__main__.person object at> 4362083472
__init__()方法,"初始化实例"时触发。
<__main__.person object at> 4362083472
----------
这是一个普通函数:cook()
Tom正在煮coffee...
----------
__call__()方法,"实例像函数一样被调用"时触发。
Tom正在自习室学习Maths...
----------
__del__()方法,"实例销毁"时触发。
2.实例的比较
__eq__(self, other):定义相等符号的行为,==
__ne__(self, other):定义不等符号的行为,!=
__lt__(self, other):定义小于符号的行为,<
__gt__(self, other):定义大于符号的行为,>
__le__(self, other):定义小于等于符号的行为,<=
__ge__(self, other):定义大于等于符号的行为,>=
代码示例:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
print('实例比较"=="时触发__eq__()')
return self.age == other.age
def __ne__(self, other):
print('实例比较"!="时触发__ne__()')
return self.age != other.age
def __gt__(self, other):
print('实例比较">"时触发__gt__()')
return self.age > other.age
def __lt__(self, other):
print('实例比较"
return self.age < other.age
def __ge__(self, other):
print('实例比较"<="时触发__ge__()')
return self.age >= other.age
def __le__(self, other):
print('实例比较"<="时触发__le__()')
return self.age <= other.age
p1, p2 = Person('Tom', 16), Person("Json", 16)
print(p1 == p2) # 触发__eq__()
print("----------")
print(p1 != p2) # 触发__ne__()
print("----------")
print(p1 > p2) # 触发__gt__()
print("----------")
print(p1 < p2) # 触发__lt__()
print("----------")
print(p1 >= p2) # 触发__ge__()
print("----------")
print(p1 <= p2) # 触发__le__()
运行结果:
实例比较"=="时触发__eq__()
True
----------
实例比较"!="时触发__ne__()
False
----------
实例比较">"时触发__gt__()
False
----------
实例比较"
False
----------
实例比较"<="时触发__ge__()
True
----------
实例比较"<="时触发__le__()
True
3.容器相关
__len__(self):len(instance)时触发
__getitem__(self, key):instance[key]时触发
__setitem__(self, key, value):instance[key]=value时触发
__delitem__(self, key, value):del instance[key]时触发
代码示例:
class Book(object):
def __init__(self, title, page_size=100):
self.title = title
self.page_size = page_size
self.li = [10, 20, 30]
def __len__(self):
print('调用"len(instance)"时触发__len__()方法')
return self.page_size
def __getitem__(self, item):
print('"调用instance[key]"时触发__getitem__()方法')
return self.li[item]
def __setitem__(self, key, value):
print('"调用instance[key]=value"时触发__setitem__()方法')
self.li[key] = value
def __delitem__(self, key):
print('"调用del instance[key]"时触发__delitem__()方法')
del self.li[key]
book = Book('maths', page_size=288)
print("这本书的页数:", len(book)) # 触发__len__()方法
print("----------")
print(book[0]) # 触发__getitem__()
print("----------")
print("before book.li:", book.li)
book[0] = 8 # 触发__setitem__()方法
print("middle book.li:", book.li)
print("----------")
del book[0] # 触发__delitem__()
print("finally book.li:", book.li)
运行结果:
调用"len(instance)"时触发__len__()方法
这本书的页数: 288
----------
"调用instance[key]"时触发__getitem__()方法
10
----------
before book.li: [10, 20, 30]
"调用instance[key]=value"时触发__setitem__()方法
middle book.li: [8, 20, 30]
----------
"调用del instance[key]"时触发__delitem__()方法
finally book.li: [20, 30]
4.迭代器
定义一个迭代器,需实现__iter__()和__next__()。
__iter__(self):调用iter(instance)时触发,返回一个迭代器
__next__(self):调用next(instance)时或对instance进行迭代时触发
代码示例:
# 自定义迭代器
class MyIter(object):
def __init__(self, total, start=0):
self.total = total
self.start = start
def __iter__(self):
print('"调用iter(instance)"时触发__iter__()')
return self
def __next__(self):
print('"调用next(instance)"时触发__next__()')
if self.start < self.total:
self.start += 1
return self.start
else:
raise StopIteration
myIter = MyIter(5)
print(next(myIter)) # 触发__next__()
print("----------")
it = iter(myIter) # 触发__iter__()
print("----------")
print(next(it)) # 触发__next__()
print("----------")
for value in it: # 进行迭代操作,触发__next__()
print(value)
运行结果:
"调用next(instance)"时触发__next__()
1
----------
"调用iter(instance)"时触发__iter__()
----------
"调用next(instance)"时触发__next__()
2
----------
"调用iter(instance)"时触发__iter__()
"调用next(instance)"时触发__next__()
3
"调用next(instance)"时触发__next__()
4
"调用next(instance)"时触发__next__()
5
"调用next(instance)"时触发__next__()