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

相关推荐

  • LAMP快速部署及LAMP组合深入讲解-2

      lamp SQL 数据管理模型:层次模型、网状模型、关系模型数据分类:结构化数据、半结构化数据、非结构化数据 关系模型 数据库:一个方案、一个项目 二维关系: 表:row, column 索引:index 视图:view SQL接口:Structured Query Language;类似于OS的shell接口;也提供编程功能; ANSI: S…

    2017-06-04
  • 用户权限

    一、用户和组的主要配置文件
    二、用户管理命令
    三、组管理命令
    四、查看用户相关的ID信息
    五、切换用户或以其他用户身份执行命令

    2018-03-13
  • Linux初识

    N22-熊宝–http://www.178linux.com/author/echeng1514 –马哥教育网络班22期–第1周课程练习   1、描述计算机的组成及其功能: 2、按系列罗列Linux的发行版,并描述不同发行版之间的联系与区别: Linux有众多的发行版,都是基于不同的内核版本,做了许多改…

    Linux干货 2016-08-15
  • shell脚本编程

    一、编程基础: shell脚本是包含一些命令或声明,并符合一定格式的文本文件 shell脚本的用途有: 自动化常用命令 执行系统管理和故障排除 创建简单的应用程序 处理文本或文件 1)     第一步:使用文本编辑器来创建文本文件 script.sh 并编写内容 格式要求:首行shebang &nb…

    Linux干货 2016-08-15
  • 在马哥学习linux第一天的感受

         来马哥教育好几天了,昨天算是正式开始,在昨天早上,举行了开班典礼,各位老师助教为我们介绍了在马哥教育进行培训的相关注意事项,下午进行了两场测试,首先有一个摸底测试,不得不说我真的是太菜了,除了一些比较简单的题目我还有些把握,相当一部分我都是似曾相识,但是也不是很确定,还有很大一部分我根本听都没听说过,看到别人都写的满满…

    Linux干货 2017-07-11
  • N28-第四周博客作业

    1、复制/etc/skel目录为/home/tuser1,要求/home/tuser1及其内部文件的属组和其它用户均没有任何访问权限。

    2、编辑/etc/group文件,添加组hadoop。

    3、手动编辑/etc/passwd文件新增一行,添加用户hadoop,其基本组ID为hadoop组的id号;其家目录为/home/hadoop。

    4、复制/etc/skel目录为/home/hadoop,要求修改hadoop目录的属组和其它用户没有任何访问权限。

    5、修改/home/hadoop目录及其内部所有文件的属主为hadoop,属组为hadoop。

    6、显示/proc/meminfo文件中以大写或小写S开头的行;用两种方式;

    7、显示/etc/passwd文件中其默认shell为非/sbin/nologin的用户;

    8、显示/etc/passwd文件中其默认shell为/bin/bash的用户;

    9、找出/etc/passwd文件中的一位数或两位数;

    10、显示/boot/grub/grub.conf中以至少一个空白字符开头的行;

    11、显示/etc/rc.d/rc.sysinit文件中以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的行;

    12、打出netstat -tan命令执行结果中以‘LISTEN’,后或跟空白字符结尾的行;

    13、添加用户bash, testbash, basher, nologin (此一个用户的shell为/sbin/nologin),而后找出当前系统上其用户名和默认shell相同的用户的信息;

    Linux干货 2017-12-26