前言
大家早好、午好、晚好吖 ❤ ~欢迎光临本文章
如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码
下面总结python内置函数对应的魔法方法
魔法方法
数学计算
-
abs(args):返回绝对值,调用__abs__;
-
round(args):返回四舍五入的值,调用__round__;
-
math.floor():向下取整,调用__floor__;
-
math.ceil():向上取整,调用__ceil__;
-
math.trunc():求一个值距离0最近的整数,调用__trunc__;
-
divmod(a,b):返回商和余,调用__divmod__;
-
pow(a,b):返回幂,调用__pow__;
-
sum():返回和,调用__sum__;
-
float():转换小数,调用__float__;
-
int():转换整数,调用__int__;
-
str():转换字符串,调用__str__;
-
sys.getsizeof():对象占内存的大小,调用__sizeof__;
-
bin(*args, **kwargs):调用参数的__bin__方法,返回整数的二进制表示形式,只支持一个参数,只支持int类型
-
hash():调用__hash__方法,获取一个对象的散列值,相等的两个数哈希值相等,反过来不一定成立
-
hex(*args, **kwargs):调用__hex__方法,求整数的十六进制表示形式,只支持Int类型
-
oct(*args, **kwargs):调用__oct__方法,求整数的八进制表示形式,只支持Int类型
访问控制
-
__getattr__(self, name)
:getattr方法触发,仅对对象未定义的属性有效,即如果视图获取一个没有的属性时会调用该方法,前提是该对象未定义 -
__getattribute__(self, name)
:getattr方法触发,如果对象定义了该方法,一定触发,__getattr__方法将不会被调用;它也可以被self.name语法糖触发;
-
__setattr__(self, name, value)
:setattr方法触发,设置一个对象的属性;也可以被self.name = ''语法糖触发。
-
__delattr__(self, name)
:delattr方法触发,删除一个对象的属性,或由del self.name 形式触发;
容器类型
在Python中实现自定义容器类型需要用到一些协议。
不可变容器类型有如下协议:
-
不可变容器,需要定义_len_· 和 ·getitem ;
-
可变容器,需要定义 len 、getitem、setitem、delitem ;
-
容器可迭代,需要定义 iter ;
-
迭代器,必须遵守迭代器协议,需要定义_iter_ 和 _next_方法。
索引语法糖与魔法方法
-
__len__(self)
:返回容器的长度; -
__getitem__(self, key)
:使用self[key]形式语法糖获取元素会触发; -
__setitem__(self, key)
:使用self[key] = 'xxx’形式复制会触发; -
__delitem__(self, key)
:使用del self[key]语法糖触发 -
__reversed__(self)
:reversed(self)触发,反转容器; -
__missing__(self, key)
:字典结构使用self[key]形式获取元素,如果元素不存在触发;
分片语法糖与魔法方法
切片在底层的原理,py2和py3有很大的不同,py2中使用_getslice_、setslice、_delslice__三个魔法方法控制,py3中将索引和切片统一由_getitem、setitem、__delitem__控制。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:702813599
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# py2中
ls = [1,2,3,4]
print(ls[1:3]) # py2中该语法糖调用__getslice__方法,py3中废弃
del ls[1:3] # py2中该语法糖调用__delslice__方法,py3中废弃
ls[1:3] = [1,2,2] # py2中该语法糖调用__setslice__方法,py3中废弃
# py3中
class Person(object):
def __getitem__(self, item):
print(item)
return 'getitem'
def __setitem__(self, key, value):
print(key, value)
return 'setitem'
def __delitem__(self, key):
print(key)
return 'delitem'
if __name__ == "__main__":
person = Person()
print(person[0]) # person[0] ==> person.__getitem__(0)
print(person[0:2]) # person[0:2] ==> person.__getitem__(slice(0,2,None))
person[0:2] = 'test' # ==> person.__setitem__(slice(0,2,None), 'test')
del person[0:2] # ==> person.__delitem__(slice(0,2,None))
# 结果
0
getitem
slice(0, 2, None)
getitem
slice(0, 2, None) test
slice(0, 2, None)
python在处理索引语法糖的时候,将索引当做参数传入相关getitem、setitem、delitem的魔法方法;
在处理切片语法糖的时候先调用slice方法得到slice实例对象,将其作为参数调用相关的魔法方法。
拷贝
copy(self):如果对象定义了该方法,copy.copy()就会调用该方法返回拷贝对象;
deepcopy(self, x):如果对象定义了该方法,copy.deepcopy()就会调用该方法返回拷贝对象;
序列化
序列化我们可以简单理解成对任何数据的一种描述方法,如果多种平台遵循了相同的序列化协议,数据之间的传递就会变得方便。
python默认的序列化模块为pickle。
序列化的简单例子
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:702813599
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Person(object):
def __init__(self):
self.name = 'cai'
if __name__ == "__main__":
import pickle
person = Person()
with open('./person.txt', 'wb') as f:
# 序列化后存储
pickle.dump(person,f)
with open('./person.txt', 'rb') as f:
# 反序列化
per = pickle.load(f)
print(per.name)
# 我们可以把一个类保存起来,后续读取它直接使用。
相关的魔法方法
-
__getinitargs__(self)
:该魔法方法在py3中似乎被废弃,原本的功能是在序列化时获取实例化参数,应该返回一个元组; -
__getnewargs__(self)
:对新式类,通过这个方法改变类在反pickle时传递给__new__ 的参数;应该返回一个参数元组。 -
__getstate__(self)
:定义对象被序列化时的状态,而不使用对象的 __dict__属性,必须返回一个字典,他会去替代 __dict__属性,在序列化时被调用; -
__setstate__(self,state)
:当一个对象被反pickle时,如果定义了__setstate__,对象的状态会传递给这个魔法方法,而不是直接应用到对象的__dict__ 属性, state参数是序列化前的__dict__属性。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:702813599
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Person(object):
def __init__(self,name):
print('init')
self.name = name
def __getinitargs__(self):
print('initargs')
return 'zhao',
def __getnewargs__(self):
print('newargs')
return 'wang',
def __getstate__(self):
print('getstate')
return {'name':'xiao'}
def __setstate__(self, state):
print('setstate')
print(state)
self.__dict__ = state
if __name__ == "__main__":
import pickle
person = Person('cai')
with open('./person.txt', 'wb') as f:
# 序列化后存储
pickle.dump(person,f)
with open('./person.txt', 'rb') as f:
# 反序列化
per = pickle.load(f)
print(per.name)
# 结果
__new__
init
newargs
getstate
__new__
setstate
{'name': 'xiao'}
xiao
说明:
pickle序列化对象之前,先执行__getnewargs__或__new__方法的参数;
然后执行__getstate__方法,返回的值替代对象的__dict__属性值;
反序列化时调用new方法,以getnewargs返回的值作为参数创建实例;
最后调用__setstate__方法,将getstate方法的返回值作为state参数;
所以由于反序列化时不会调用init方法初始化,getinitargs和getnewargs方法的作用都变得不大;
其他
-
__instancecheck__(self, instance)
:instance触发,判断对象的类型 -
__subclasscheck__(self, subclass)
:issubclass触发,判断一个对象是另一个对象的子类; -
__call__
:callable触发,判断一个对象是否可调用; -
__dir__(self)
:dir()触发,获取对象的所有属性、方法的名字组成的列表;
__str_和_repr
调用str触发_str_,调用repr()触发_repr_,
但是print()也可以触发__str_和_repr,
如果对象定义了_str_,则print()一般触发_str_,否则触发_repr_;
但列表以及字典等容器总是会使用_repr_ 方法.
__str__和__repr__的区别
一般来说,str 的返回结果在于强可读性,而 repr 的返回结果在于准确性;
默认情况下,在需要却找不到 __str__方法的时候,会自动调用 _repr_方法。
总结
熟悉了python语法糖、内置函数与魔法方法之间的关系后,显然对于如何写好一个优雅易用的类有很大的帮助。
尾语
好了,今天的分享就差不多到这里了!
对下一篇大家想看什么,可在评论区留言哦!看到我会更新哒(ง •_•)ง
喜欢就关注一下博主,或点赞收藏评论一下我的文章叭!!!