1.下面便是python中常见的魔术方法和其功能:
魔术方法名称 | 功能 |
__name__ | 类、函数、方法等的名字 |
__module__ | 类定义所在的模块 |
__class__ | 对象或类所属的类 |
__bases__ | 当前类的基类(父类) |
__doc__ |
类、函数的文档帮助,没有定义为
None
|
__mro__ | Method Resolution Order 方法解析顺序 |
__dict__ | 类或实例的属性,可写的字典 |
部分饰演效果如下:
from functools import lru_cache
class Fib(object):
@lru_cache(maxsize=1000)
def __call__(self, n):
if n in (1, 2):
return 1
else:
return self(n-1) + self(n-2)
fib = Fib()
print(fib(10))
测试结果:
55
from functools import wraps
import time
def timeit(unit='s'):
def wrapper1(fun): # fun=add
@wraps(fun)
def wrapper(*args, **kwargs):
if unit == 's':
start_time = time.time()
result = fun(*args, **kwargs) # add(1, 2) result=3
end_time = time.time()
print("%s函数运行时间为%.2f s" %(fun.__name__, end_time-start_time))
return result
else:
print("当前功能不支持......")
return wrapper
return wrapper1
# 类装饰器: 装饰器需要传递的参数通过__init__传递进入.被装饰函数执行的内容在__call__魔术方法中编写。
class TimeIt(object):
def __init__(self, unit='s'):
self.unit = unit
def __call__(self,fun):
@wraps(fun)
def wrapper(*args, **kwargs):
if self.unit == 's':
start_time = time.time()
result = fun(*args, **kwargs) #add(1, 2) result=3
end_time = time.time()
print("%s函数运行时间为%.2f s" % (fun.__name__, end_time - start_time))
return result
else:
print("当前功能不支持......")
return wrapper
# @timeit(unit='s') # @wrapper1 ==> add = wrapper1(add) ===> add = wrapper
# def add(num1, num2):
# time.sleep(0.333)
# return num1 + num2
"""
@TimeIt(unit='h')
# 1). TimeIt_obj = TimeIt(unit='h')
# 2). @TimeIt_obj
# 3). add=TimeIt_obj(add)
# 4). add = wrapper
"""
@TimeIt(unit='s')
def add(num1, num2):
time.sleep(0.333)
return num1 + num2
add(1, 2)
from functools import partial
max_100 = partial(max,10, 100) # 返回对象
print(max_100(1, 2, 3))
测试结果:
100
4)应用范例四: call魔术方法实现函数式编程
class partial:
def __new__(cls,func,*args,**kwargs):
if not callable(func):
raise TypeError("the first argument must be callable")
self = super().__new__(cls)
self.func = func
self.args = args
self.kwargs = kwargs
return self
def __call__(self,*args,**kwargs):
return self.func(*self.args,*args,**self.kwargs,**kwargs)
max100 = partial(max,10,20,100)
max_num = max100(1,2,3,4)
print(max_num)
100
注意:calable() 函数用于检查一个对象是否是可以调用的(有没有__call__模式方法)。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __int__(self):
return int(self.age)
def __repr__(self):
return 'Person<%s>' %(self.name)
p1 = Person("fentiao", '100')
print(p1)
print(int(p1))
Person
100
magic method | explain |
__init__(self) | 转换成整形 |
__long__(self) | 转换成长整形 |
__float__(self) | 转换成浮点型 |
__complex__(self) | 转换成复数型 |
__oct__(self) | 转换成八进制 |
__hex__(self) | 转换成十六进制 |
__index__(self) | 如果定义了一个可能被用来做切片操作的数值类型, 就应该定义index |
__trunc__(self) | 当math.trunc(self)使用时被调用__trunc__返回自身类型的 整型截取 |
__coerce__(self,other) | 执行混合类型的运算 |
class Student(object):
def __init__(self, name, scores):
self.name = name
self.scores = scores
def __getitem__(self, index):
"""实现获取索引和切片值的魔术方法"""
print(index)
return self.scores[index]
def __setitem__(self, index, value):
"""实现修改/设置索引和切片值的魔术方法"""
self.scores[index] = value
def __delitem__(self, index):
del self.scores[index]
def __mul__(self, other):
"""重复操作"""
return self.scores * other
def __add__(self, other):
"""连接操作, 传入的对象"""
return [ item[0]+item[1] for item in zip(self.scores, other.scores)]
def __contains__(self, item):
"""成员操作符"""
return item in self.scores
def __iter__(self):
# iter可以将可迭代对象转换成迭代器(可以调用next方法的)
return iter(self.scores)
stu1 = Student("张三", [100, 90, 100])
stu2 = Student("李四", [100, 80, 100])
#1). 索引和切片的测试
print(stu1[1:]) # 获取索引/切片值
stu1[1:] = (80, 80) # 设置索引/切片对应的value值
print(stu1.scores)
del stu1[1:] # 删除索引/切片值
print(stu1.scores)
for item in stu1:
print(item)
测试结果:
slice(1, None, None)
[90, 100]
[100, 80, 80]
[100]
100
class Student(object):
def __init__(self, name, scores):
self.name = name
self.scores = scores
def __getitem__(self, index):
"""实现获取索引和切片值的魔术方法"""
print(index)
return self.scores[index]
def __setitem__(self, index, value):
"""实现修改/设置索引和切片值的魔术方法"""
self.scores[index] = value
def __delitem__(self, index):
del self.scores[index]
def __mul__(self, other):
"""重复操作"""
return self.scores * other
def __add__(self, other):
"""连接操作, 传入的对象"""
return [ item[0]+item[1] for item in zip(self.scores, other.scores)]
def __contains__(self, item):
"""成员操作符"""
return item in self.scores
def __iter__(self):
# iter可以将可迭代对象转换成迭代器(可以调用next方法的)
return iter(self.scores)
stu1 = Student("张三", [100, 90, 100])
stu2 = Student("李四", [100, 80, 100])
# 2)连接、重复和成员操作符
print(stu1*3)
print(stu1 + stu2)
print(150 in stu1)
[100, 90, 100, 100, 90, 100, 100, 90, 100]
[200, 170, 200]
False
def __iter__(self): #迭代,使得该对象实现for循环
#将列表转换为迭代的类型,可以for循环,一定要返回iter类型的数据;
return iter(self.scores)
#7)实现for循环?
for item in liming:
print(item)
import contextlib
import tempfile
import shutil
@contextlib.contextmanager
def make_temp_dir():
try:
tmp_dir = tempfile.mkdtemp()
yield tmp_dir
finally:
shutil.rmtree(tmp_dir)
with make_temp_dir() as f:
pass
测试结果:
with语句执行之后......
Process finished with exit code 0
方法二: 基于类的上下文管理器: 只要一个类实现了 __enter__() 和 __exit__() 这 2 个方法,程序就可以使用 with as 语句来管理它。
class Myopen(object):
def __init__(self,name,mode='r'):
self.name=name
self.mode=mode
def __enter__(self):
#当with语句进入并开始执行时,执行的内容,
#需要返回一个对象,在执行结束后用来关闭或者其他操作:
self.f=open(self.name,self.mode)
print("正在打开文件%s......" %(self.name))
return self.f
def __exit__(self,exc_type,exc_val,exc_tb):
#with语句执行结束后,做什么操作
self.f.close()
print("文件正在关闭.....")
测试结果:
文件正在关闭.....
案例:基于call魔术方法和filter实现文件过滤器
import os
# 作为基类/父类
class FileAcceptor(object):
def __init__(self, accepted_extensions):
"""
eg: ['.png', '.jpg']
:param accepted_extensions: 可以接受的扩展名
"""
self.accepted_extensions = accepted_extensions
def __call__(self, filename):
"""
eg: hello.jpg
:param filename: 需要判断的文件名
:return:
"""
# base = 'hello', ext='.jpg'
base, ext = os.path.splitext(filename)
return ext in self.accepted_extensions
# 子类
class ImageFileAcceptor(FileAcceptor):
def __init__(self):
image_ext = ('.jpg', '.jepg', '.png')
super(ImageFileAcceptor, self).__init__(image_ext)
# 子类
class ExcelFileAcceptor(FileAcceptor):
def __init__(self):
image_ext = ('.xls', '.xlsx')
super(ExcelFileAcceptor, self).__init__(image_ext)
if __name__ == '__main__':
filenames = [
'hello.jpg',
'hello.xls',
'hello.txt'
]
"""
1). ImageFileAcceptor() 实例化对象, 执行__new__和__init__魔术方法。
2). imagefileacceptor_obj
3). imagefileacceptor_obj('hello.jpg') True
3). imagefileacceptor_obj('hello.xls') False
3). imagefileacceptor_obj('hello.txt') False
4). ['hello.jpg']
"""
images_file = filter(ImageFileAcceptor(), filenames)
excels_file = filter(ExcelFileAcceptor(), filenames)
print(list(images_file))
print(list(excels_file))
测试结果:
['hello.jpg']
['hello.xls']