python面向对象第二周魔术方法详解

魔法方法及其使用
__开头和结束的方法,定义外部没有办法直接调用,但会有影响使用
运算符号的魔法方法, + ,-,*,/,%,//,**, __add__,__sub__,__mul__,__truediv__,__mod__,__floordiv__,__pow__,
__divmod__(?),
系统内部对于数值型,字符串型,容器内型都定义了其中部分或者全部的运算符使用要求和办法,
我们在类中定义这些魔法方法,可以使得它们按照需要对对象类型进行运算符运算, 仍需要满足一些基本的概念
比如加减乘除都是在两个对象而言的,所以形参数量要为二 ,且其中一个为self(类自身的对象)其他大部分的运算符魔法方法对于参数数量和类型也有类似要求,
其他变种运算符 +=,-=,*=,/=,%=,//=,**= ,它们的魔法方法写法就是相应的名称前加一个i,它们对于形参数和类型也与前面的类似
判断运算符 <,<=,==,>,>=,!=
和运算符号的一样,他么的返,定义一般要求两个参数,且其中一个为self(类自身的对象),它们不一定要求返回布尔型的值,可以没有或者返回其他类型的值
在使用这些运算符对系统数据类型使用这些符号时不会有覆盖,或者不能使用的问题,因为他们内部的类中有魔法方法定义使用这些符号的使用规则,即使我们在自定义的类中对基本数据类型时使用运算符,依然能够准确表达含义

容器相关方法:__len__,__iter__,__contains__,__getitem__,__setitem__,__missing__
获取长度,迭代器, in运算符,索引访问,索引设置,其它
容器相关方法,在基本数据类型中的容器类型,list,tuple,set,dict中有实现其中大部分或全部方法,
对他们调用 len( ),可以使用是因为实现了__len__的魔法方法,在类中可以定义它,使得我们也可以在外部调用该方法,这个方法要求只有一个形参,且为类的对象,要有返回值且为整型,使用 len(对象)会调用这个方法
当迭代一个对象(使用for in 遍历)时会调用__iter__的方法,获取该方法返回的迭代器,for in 遍历的实质是遍历这个迭代器,所以这个对象可以被成为可迭代对象,任何数据类型如果实现__iter_就是一个可迭代类型. 实现__iter__
方法要求传入一个参数,为self(类自身的对象)返回一个迭代器 (iter( )函数,yield from iterable都可以返回一个迭代器)
__contains__(self,item) 使用判断语句 in 的时候调用的方法 如果使用 ” item in 对象 ” 就会调用这个方法
如果没有定义该方法依然可以使用,in 语句 自是他会自动调用 对象的 __iter__方法获取它的迭代器 相当于对对迭代器使用 in 语句. __contains__ 方法要求有返回值且为布尔型,若不为布尔型根据返回值是否为空类型返回True 或 False
索引访问 对象[ ] ,调用__getitem__方法 __getitem__(self,item) item为索引
形参只能为两个(如果不定义两个调用时将会出现无法处理的错误),item为传入中括号中的值,但系统对这个值要求非常松,可以为任意类型
使用索引赋值(赋值即定义) 对象[ ] =值 ,调用__setitem__方法 __setitem__(self,key,value) key为中括号中的值,value为等号右边的值
其他 __missing__, 当调用了__getitem__()方法,而key不存在就会调用这个方法(只能被动的调用)

总结:魔法方法,在使用中不像普通方法一样调用方法名就能够使用,他是系统中设置好的,我们在类中能够对它重写,对于运算符,重写的要求很简单,传入两个参数对于函数内部实现没有要求. 对于函数体实现没有要求.
对于容器类型的相关方法,它的参数可能要求很低,但使用中可能会出错,很多对于返回值也有要求,要求有且返回
指定类型. 实际在一个容器中,对于函数的实现它的要求其实会更高,例如它要实现索引设置和获取,要求把设置的内容保存,获取时从内部获取.基本数据类型中除了容器类型,还有其他类型实现了其中的部分方法

对象的打印,正常使用print函数打印一个对象会获得<__main__.A object at 0x00000272662DF6A0>这样的结果
__repr__ , __str__ 两个方法可以作为对象的显示方法
在print 和 format 函数中如果要打印对象会优先调用__str__方法, 如果打印一个包装了对象的基本数据类型的时候,会先执行打印基本数据类型的方法,其中的对象只会调用对象的__repr__方法

可调用对象__call__ 如果一个对象可以像函数一样的访问,因为实现了这个方法,对参数,返回值没有要求
__enter__,__exit__,使用条件苛刻,上下文管理(with语句)时才会执行,这两个方法都是被动调用的

@functools.total_ordering装饰器
类中实现包含等于,包含大于小于之一的两个方法就会实现六个方法

反射相关魔术方法:
首先看看反射相关的内建函数 getattr(对象,name[,default]) 通过name(字符串类型) 获取对象中叫作name的属性,没有就返回default,没设置会报错
setattr(对象,name,value) 设置对象的属性和值,有就覆盖,没有就新增
hasattr(对象,name) 判断对象是否有这个名字的属性
__getattr__(self,item) 外部对对象使用 对象.name 访问时,访问字典不能得到,最后执行的方法
__setattr__(self,key,value) 需要通过 对象.key = value 来为对象添加属性的时候自动调用,并拦截添加或覆盖操作,需要在其中重写这个方法,或用属性字典手动添加
__delattr__ 使用del语句删除对象时调用,并拦截删除
__getattribute__ 获取对象属性时会优先执行,如果要能正常执行获得真实结果返回
return object.__getattribute__(self.item)

总结:魔术方法,如果定义只要满足调用的条件就会自动的触发,暂时没有出现可以自行设置触发条件的魔术方法.
方法中,系统实现的部分直接或间接指示了参数含义,如果不顺着系统意思,在实际调用中可能会出现意想不到的错误. 类中的方法在实现时如果满足类中定义的魔术方法触发条件,将会触发. 魔术方法除了有方便应用和表达含义的符号,还有的实现特殊功能的,比如上下文管理 ,__call__外部访问,这些方法极大地扩展了类的功能.
显示和反射有关的魔术方法都属于工程,工具类型的魔术方法

描述器和它的三个魔术方法
:__get__ (self,instance,owner), __set__(self,instance,value) , __delete__(self, instance)
__get__ 外部的类的属性(类变量)访问就会调用,这个方法, 对象如果通过类变量访问,也会调用,它的返回值为访问到的值
__set__ 外部的类中设置对象属性值会调用,并拦截对象属性的设置

一个类中如果有这几个方法之一它就是一个描述器
如果一个类中的类属性(类变量)引入了一个描述器对象, 修饰器就能够作用于这个类. 满足条件的情况就会调用描述器中的方法. 分为很多情况
1,只有__get__, 描述器被类访问,会调用描述方法,且类变量的值为它的返回值,如果它对象通过类变量访问到修饰器,也会执行相同的操作
2,只有__set__, 在类的内部或外部,给类的对象添加或修改与描述器变量名相同的属性, 会触发描述器方法,它的返回值没有意义
3,有__del__, 在外部使用del 作用对象访问的,与描述器变量名想同的属性时,会调用 ,如果是用类访问到的不会调用

对于一个描述器有多个这样的方法,如果满足各自的条件就会触发访问,其中只有__get__为 非数据描述器
有__get__和__set__成为为数据描述器. 描述器的使用大概分为三块:1,定义描述器2,生成被描述的类并加载描述器3,外部调用被描述类的属性触发描述方法,后两种它可以起到对特定属性的监视作用.
数据描述器功能比非数据描述器强大

应用实例定义一个静态方法装饰器
class StaticMtd:
def __init__(self,fn):
self.fn = fn
def __get__(self, instance, owner):
print(‘get’)
return self.fn
def __set__(self, instance, value):
print(self,instance,value)
print(‘set’)
class A:
@StaticMtd # add = StaticMtd(add) 相当与引入了一个描述器
def add(x,y):
print(x,y)
A.add(4,5) #使用类访问触发描述器的方法
a =A()
a.add = 3 #使用对象添加与描述器变量名相同属性,触发set方法

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/88806

(1)
daishitongdaishitong
上一篇 2017-11-21 20:32
下一篇 2017-11-23 13:38

相关推荐

  • 图文演示Netmeeting的三大功能

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://jeffyyko.blog.51cto.com/28563/153578     可能很多朋友对Netmeeting有一定认识,但我想真正用过的朋友应该不多,因为类似的软件太多太多了,所以Netmeet…

    Linux干货 2015-03-25
  • rsync+inotify实现数据同步——双向传输

    实验环境:<仅2台主机之间进行数据双向传输> A主机:10.1.43.102 B主机:10.1.43.103 一、数据从A推向B 配置流程 先在B主机上配置: 1.vi /etc/rsyncd.conf(用户,目录,模块,虚拟用户及密码文件) uid = root gid = root port …

    Linux干货 2016-10-27
  • bash shell 循环语句的使用

    条件选择if语句       if语句是选择执行的,条件满足则执行,不满足则退出,if语句也可嵌套,就是if语句里面也可以在进行if语句 单分支 if 判断条件;then statement1 fi   双分支 if 判断条件;then 条件为真得分支 else 条件为假的分支 fi   …

    Linux干货 2016-08-18
  • 功能强大的Linux文本编辑器之Vim的使用

    VIM编辑器   Vim章节的内容:    使用vi和vim的三种主要模式    移动光标,进入插入模式    改变、删除、复制文本    撤销改变    搜索文档    vim寄存器    可视化和多窗口 &…

    Linux干货 2016-08-12
  • Linux下find命令的使用

    为什么要使用find命令?     Linux系统中有着成千上万的文件,如果你想要找到自己想要的文件,一款查找软件是必不可少的,而locate是根据其生成的数据库进行查找,虽然速度会略快,但非实时查找,有些新的文件或目录是匹配不到的,而且locate是模糊匹配,而find命令为实时查找,且为精确匹配,如果你对目录的权限…

    Linux干货 2016-08-18
  • Linux基础之—基础权限和特殊权限以及FACL权限管理

    Linux是多用户多任务的操作系统,了解掌握Linux的权限分配机制,也是管理Linux系统安全的基础之一。 文件目录的权限格式如下:   1.其中权限位可以看对象到是一个9个占位符,其实分为三位一组: (1) 第一组:对应的是文件或目录的所有者属主权限。owner (2) 第二组:对应的是文件或目录的所属组权限。group (3) 第三组:对应的…

    Linux干货 2016-08-07