在Python中,所有用"__"包起来的方法,都称为【魔术方法】(eg: __ len __, __ init __)。
目录
1. 特殊属性
1.__ name __
2.__ module __
3. __ class __
4.__ bases __
5.__ doc __
没有定义帮助文档的话,则为None
6. __ mro __
多继承里可以查看继承的搜索顺序
7.__ dict__
8.__ dir__ 返回类或者对象的所有成员名称列表。 查看属性
dir() 函数就是调用__ dir __()。
查看属性
1). 如果dir([obj]) 参数obj包含方法 dir(),该方法将被调用。
2). 如果Obj 不包含 dir(),该方法将最大限度收集属性信息
2.创建,初始化与销毁
面试常问: python 中__new__ , __ init__ , __call__的区别?
1). new的功能是在生成对象之前执行的内容,接受的参数是cls 类, 负责对象的创建
2). init的功能是在对象生成之后执行的内容, 接受的参数是self 对象, 负责对象的初始化
3). call的功能是在调用对象时执行的内容, 可以模拟函数的行为.
当我们新建一个对象 x=someclass() 的时候,经历的步骤:
1). 第一: __new__先创建类并返回类的实例。
2). 第二: 自动调用__init__来初始化实例对象的值。
3). 汇总: 第一步和第二步共同构成了【构造函数】。
4). 第三步: 对象生命周期调用结束时, __del __ 方法(构析函数)会被调用。
"""
1). new的功能是在生成对象之前执行的内容,接受的参数是cls 类, 负责对象的创建
2). init的功能是在对象生成之后执行的内容, 接受的参数是self 对象, 负责对象的初始化
3). call的功能是在调用对象时执行的内容, 可以模拟函数的行为.
"""
class Person(object):
def __new__(cls):
print("__new__")
return object.__new__(cls)
def __init__(self):
print("__init__")
def __call__(self, *args, **kwargs):
print('__call__')
def __del__(self):
# 析构方法: 当对象被删除或者从内存释放时自动执行
print("__del__")
现在来看调用:
p1 = Person()
p1()
首先实例化出来一个p1对象,因此首先执行new给对象开辟空间返回一个对象,其次执行init初始化对象。再调用p1(),调用对象时会执行call函数。程序结束后,内存释放,自动调用了析构函数del。
2.1 new魔术方法实现单例模式
在上一篇博文最后已经介绍过了
2.2 call魔术方法实现缓存
from functools import lru_cache
class Fib(object):
@lru_cache(maxsize=1000)
def __call__(self, num):
if num in (1,2):
return 1
else:
return self(num-1)+self(num-2)
if __name__ == '__main__':
fib = Fib()
print(fib(100))
???和直接用@lru_cache装饰器没区别啊???
还有其他实现方式吗???
2.3 call魔术方法实现类装饰器
这里我们还是以计算程序运行时间为例来写装饰器:
from functools import wraps
import time
用函数实现的装饰器如下:
def timeit(func):
@wraps(func)
def wrapper(*args,**kwargs):
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print('%s执行了%.3f' %(func.__name__,end-start))
return result
return wrapper
@timeit
def count(n):
while n>0:
n-=1
调用一下看结果:
if __name__ == '__main__':
count(1000000)
如果要用call魔术方法实现类装饰器,很简单,在这个基础上进行改动。
class timeit(object):
def __call__(self,func):
@wraps(func)
def wrapper(*args,**kwargs):
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print('%s执行了%.3f' %(func.__name__,end-start))
return result
return wrapper
@timeit() #--->timeit实例化出来一个对象timeit_obj
# 再用这个count=timeit_obj(count)
def count(n):
while n>0:
n-=1
类装饰器的优点体现在当我们要为这个装饰器传递参数时,普通做法是在原有的装饰器外面加一层,但是类装饰器直接加一个__ init__()初始化方法,将参数传递给这个初始化方法,封装起来,在call方法中调用即可。
普通做法:
def timeit(type='s'):
def wrapper1(func):
@wraps(func)
def wrapper(*args,**kwargs):
if type == 's':
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print('%s执行了%.3f' %(func.__name__,end-start))
return result
else:
print('尚未开通此功能')
return wrapper
return wrapper1
@timeit('h')
def count(n):
while n>0:
n-=1
类装饰器的做法:
class timeit(object):
def __init__(self,type = 's'):
self.type = type
def __call__(self,func):
@wraps(func)
def wrapper(*args,**kwargs):
if self.type == 's':
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print('%s执行了%.3f' %(func.__name__,end-start))
return result
else:
print('尚未开通此功能')
return wrapper
@timeit('h') #------>timeit实例化出来一个对象timeit_obj 再用这个count=timeit_obj(count)
def count(n):
while n>0:
n-=1
2.4 call魔术方法实现偏函数
偏函数(2.5+) partial function。通过有效地“冻结”预先确定的参数,来缓存函数参数。运行时获得剩余参数后,解冻并传递到函数中。系统内置的偏函数操作范例如下:
from functools import partial
max_100 = partial(max,10, 100) # 返回对象
print(max_100(1, 2, 3))
用new方法和call方法对偏函数的实现如下:
2.5 call魔术方法实现函数式编程
回忆一下map、filter
map:
filter:
Python中的函数式编程功能,如map()、filter()、reduce(),可以使用可调用对象。下面是使用
可调用对象和filter()根据文件名扩展名过滤文件的代码。
import os
class FileAcceptor(object):
def __init__(self,accepted_extention):
"""
eg: ['.png', '.jpg']
:param accepted_extensions: 可以接受的扩展名
"""
self.accepted_extention = accepted_extention
def __call__(self, filename):
"""
eg: hello.jpg
:param filename: 需要判断的文件名
:return:
"""
base, ext = os.path.splitext(filename)
return ext in self.accepted_extention
class ImageFileAcceptor(FileAcceptor):
def __init__(self):
image_ext = ('.jpg', '.jepg', '.png')
super(ImageFileAcceptor, self).__init__(image_ext)
class ExcelFileAcceptor(FileAcceptor):
def __init__(self):
excel_ext = ('.xls','.xlsx')
super(ExcelFileAcceptor, self).__init__(excel_ext)
class TextFileAcceptor(FileAcceptor):
def __init__(self):
text_ext = ('.txt','.doc')
super(TextFileAcceptor, self).__init__(text_ext)
filename = [
'sdkfj.png',
'sdkf.jpg',
'sdfwer.png',
'lkjl.xls',
'sdfkhjk.doc'
]
imagefileaccptor = ImageFileAcceptor()
exclefileaccptor = ExcelFileAcceptor()
textfileaccptor = TextFileAcceptor()
print(list(filter(imagefileaccptor,filename)))
print(list(filter(exclefileaccptor,filename)))
print(list(filter(textfileaccptor,filename)))
3.可视化
类型判断要使用type或isinstance, 不能通过判断print输出是否带引号来判断输出值的类型。
1). str()与repr()都是python中的内置函数,是直接用来格式化字符串的函数。
2). 当使用内置函数str(obj)时, 自动执行obj.str()魔术方法。
3). 当使用内置函数repr(obj)时, 自动执行obj.repr()魔术方法。
4). 当__str__魔术方法不存在时, 自动执行__repr__()魔术方法的内容。
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("xiaoming", '20')
print(p1)
print(int(p1))
4. 类型转换
5. 索引与切片
注:slice() 函数实现切片对象,主要用在切片操作函数里的参数传递。
索引&切片魔术方法:
__ setitem__:当属性被以索引、切片方式赋值的时候会调用该方法
__ getitem__:一般如果想使用索引、切片访问元素时,就可以在类中定义这个方法
__ delitem__:当使用索引、切片删除属性时调用该方法
class Student(object):
def __init__(self, name, scores):
self.name = name
self.scores = scores
def __getitem__(self, index):
"""实现获取索引和切片值的魔术方法"""
return self.scores[index]
def __setitem__(self, index, value):
"""实现修改/设置索引和切片值的魔术方法"""
self.scores[index] = value
def __delitem__(self, index):
del self.scores[index]
if __name__ == '__main__':
st1 = Student('xiaoming',[100,80,90,200,180])
print(st1.scores)
print(st1[1:4])
st1[2] = 111
print(st1.scores)
del(st1[1])
print(st1.scores)
6.重复,连接与成员操作符
class Student(object):
def __init__(self, name, scores):
self.name = name
self.scores = scores
def __mul__(self, other):
"""重复操作"""
return self.scores * other
def __add__(self, other):
"""连接操作, 传入的时对象"""
return [ item[0]+item[1] for item in zip(self.scores, other)]
##也可以 return self.scores+other (看个人逻辑)
def __contains__(self, item):
"""成员操作符"""
return item in self.scores
if __name__ == '__main__':
st1 = Student('xiaoming',[100,80,90,200,180])
print(st1*3)
print(st1+[1,2,3,4])
print(100 in st1)
7.循环
class Student(object):
def __init__(self, name, scores):
self.name = name
self.scores = scores
def __iter__(self):
# iter可以将可迭代对象转换成迭代器(可以调用next方法的)
return iter(self.scores)
st1 = Student('xiaoming',[100,80,90,200,180])
for item in st1:
print(item)
8.比较大小
class Int(object):
def __init__(self, number, weight):
self.number = number
self.weight = weight
def __gt__(self, other):
"""判断大于的魔术方法"""
return self.number * self.weight > other.number * other.weight
def __ge__(self, other):
"""判断大于等于的魔术方法"""
return self.number * self.weight >= other.number * other.weight
def __eq__(self, other):
"""判断等于的魔术方法"""
return self.number * self.weight == other.number * other.weight
i1 = Int(20, 3)
i2 = Int(20, 3)
print(i1 > i2)
print(i1 < i2)
print(i1 >= i2)
print(i1 == i2)
print(i1 != i2)
9.魔术方法总结
基本的魔法方法
有关属性的魔术方法
比较操作符
算数运算符
反运算
增量赋值运算
一元操作符
类型转换
上下文管理(with 语句)
容器类型