面向对象魔术方法

##**特殊属性**
– __name__ 类、函数、方法等的名字
– __module__ 类定义所在的模块名
– __class__ 对象或类所属的类
– __bases__ 类的基类的元组,顺序为它们在基类列表中出现的顺序
– __doc__ 类、函数的文档字符串,如果没有定义则为None
– __mro__ 类的mro,class.mro()返回的结果的保存在__mro__中
– __dict__ 类或实例的属性,可写的字典

##**查看属性**
– __dir__
– 返回类或者对象的所有成员名称列表。dir()函数就是调用__dir__()。如果提供__dir__(),则返回属性的列表,否则会尽量从__dict__属性中收集信息
– dir对于不同类型的对象具有不同的行为
– 对象是模块,列表包含模块的属性名
– 对象是类型或者类对象,列表包含类的属性名,及它的基类的属性名
– 否则,列表包含对象的属性名,它的类的属性名和类的基类的属性名
###举例
a = Cat(‘tom’)
print(dir()) #从这往下类型数量依次递加
print(dir(Animal))
print(dir(Animal.__dict__))
print(dir(a.__dict__))

##**魔术方法**
– __hash__ 内建函数hash()调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash
– __hash__方法返回hash的值做为set的key,但是去重,还需要__eq__来判断是否相等
– hash相等只能说明hash冲突,不能说明两个对象相等
– 可hash的对象必须提供__hash__方法,没有提供的话,isinstance(p1,collections.Hashable)一定为False
– __eq__ 对应 == 操作符,判断两个对象是否相等,返回bool值
– __bool__ 没有定义__bool__就找__len__()返回长度,非0为真。如果__len__()也没有定义,那么所有实例都返回真
###举例
class A:
def __init__(self):
self.a = ‘a’
self.b = ‘b’

def __hash__(self):
return 123 # hash恒定的值

def __eq__(self, other):
return self.a == other.a #判断是否相等 如果return False便不相等 return True相等

print(bool(A())) # True # 若定义__len__,return 0 则返回False
print(hash(A()))
print((A(),A()))
print({A(),A()})
s = {A(),A()}
print(s)

###**可视化**
– __repr__ 内建函数repr()对一个对象获取字符串表达。如果一个类定义__repr__(),但没有定义__str__,那么在请求该类的实例的“非正式”的字符串表示时也将调用__repr__()
– __str__ str()函数、内建函数format、print()函数调用,需要返回对象的字符串表达
– __bytes__ bytes的时候,返回一个对象的bytes表达,即返回bytes对象

##**运算符重载**
– < : __lt__ <= : __le__ == : __eq__ > : __gt__ >= : __ge__ != : __ne__
– + : __add__ – : __sub__ * : __mul__ / : __truediv__ % : __mod__
– // : __floordiv__ ** : __pow divmod : __divmod__
– += : __iadd__ -= : __isub__ *= : __imul__ /= : __itruediv__ %= : __imod__
– //= : __ifloordiv__ **= : __ipow__

###练习
class A:
def __init__(self,x):
self.x = x
def __sub__(self,other):
return self.x – other.x
def __isub__(self,other):
tmp = self.x – other.x
return A(tmp)
def __str__(self):
return str(self.x)
x = A(5)
y = A(4)
print(x-y,x.__sub__(y))
x -= y
print(x)

##**运算符重载应用场景**
###**容器相关方法**
– __len__ 内建函数len(),返回对象的长度(>=0的整数),其实即使把对象当做容器类型看,就如同list或者dict。bool()函数调用的时候,如果没有__bool__()方法,则会看__len__()方法是否存在,存在返回非0为真
– __iter__ 迭代容器时,调用,返回一个新的迭代器对象
– __contains__ in成员运算符,没有实现,就调用__iter__方法遍历
– __getitem__ 实现self[key]访问。序列对象,key接受整数为索引,或者切片。对于set和dict,key为hashable。key不存在引发KeyError异常
– __setitem__ 和__getitem__的访问类似,是设置值的方法
– __missing__ 字典使用__getitem__()调用是,key不存在执行该方法
###购物车用容器相关方法
class Item:
def __init__(self,name,**kwargs):
self.name = name
self.__spec = kwargs

def __repr__(self):
return str(self.name)

class Cart:
def __init__(self):
self.lst = []

def additem(self,item:Item):
self.lst.append(item)

def __add__(self, other):
self.lst.append(other)
return self

def __getitem__(self, index):
if isinstance(index,int):
return self.lst[index]
return None

def __iter__(self):
return iter(self.lst)

def __len__(self):
return len(self.lst)

def __setitem__(self, key, value):
self.lst[key] = value

a = Item(‘audi’,price = 100000,color = ‘black’)
b = Cart()
b.additem(a)
b+’fengtian’+”leike”+”teslia”
print(b[2])

##**可调用对象**
– __call__ 类中第一个该方法,实例就可以像函数一样调用
– 可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用
###举例
(1)
classs Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __call__(self,*args,**kwargs):
return “Point({},{})”.format(self.x,self.y)
p = Point(4,5)
print(p)
print(p())
(2)定义一个斐波那契数列的类,方便调用计算第n项
class Fib:
def __init__(self):
self.lst = [0,1,1]

def __call__(self, index):
if index < 0:
raise IndexError(“wrong index”)

if index < len(self.lst):
return self.lst[index]

for i in range(3,index+1):
self.lst.append(self.lst[i-2] + self.lst[i-1])
return self.lst[index]

def __iter__(self):
return iter(self.lst)

def __len__(self):
return len(self.lst)

def __str__(self):
return str(self.lst)

__repr__ = __str__

fib = Fib()
print(fib(100),len(fib))
for x in fib:
print(x)

##**上下文管理**
– 文件IO操作可以对文件对象使用上下文管理,使用with…as语法
– 仿照上面,自己的类也可以实现上下文管理
– 当一个文件同时实现了 __enter__()和__exit__()方法,它就属于上下文管理对象
– __enter__ 进入与此对象相关的上下文。如果存在该方法,with语法会把该方法的返回值作为绑定到as子句中指定的变量上
– __exit__ 退出与此对象相关的上下文
>实例话对象的时候,并不会调用enter,进入with语句块调用__enter__方法,然后执行语句体,最后离开with语句块的时候,调用__exit__方法
###例子
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
def __exit__(self,exc_type,exc_val,exc_tb):
print(‘exit’)
with Point() as f:
print(‘do something’)

##**上下文管理的安全性及注意点**
– 不管上例子with语句块中是否是raise抛异常还是sys.exit(),enter和exit还是照常执行得。说明上下文管理很安全
– 如果想要with p as f: 中p和f相等。那么enter返回的要是self对象。

##enter方法和exit方法的参数
– __enter__ 没有其他参数
– __exit__ 方法有3个参数
– __exit__ (self,exctype,excvalue,traceback),这三个参数都与异常有关
– exc_type 异常类型
– exc_value 异常的值
– traceback 异常的追踪信息
– __exit__方法返回一个True,则异常会被压制,正常输出需要输出的内容

###**类装饰器练习**
import time
import datetime
from functools import wraps

class TimeIt:
def __init__(self,fn):
self.fn = fn
wraps(fn)(self)

def __enter__(self):
self.start = datetime.datetime.now()

def __call__(self, *args, **kwargs):
self.start = datetime.datetime.now()
ret = self.fn(*args, **kwargs)
self.delta = (datetime.datetime.now() – self.start).total_seconds()
print(self.delta)
return ret

def __exit__(self, exc_type, exc_val, exc_tb):

self.delta = (datetime.datetime.now() – self.start).total_seconds()
print(self.delta)

@TimeIt #add = TimeIt(add) 此时的add是个对象,所以可以调用add.__doc__
def add(x,y): #类装饰器用不到enter和exit函数
“””
this is add method
“””
time.sleep(2)
return x + y

print(add(1,2))
print(add.__doc__)

##**上下文应用场景**
– 增强功能
– 在代码执行的前后增加代码,以增强其功能。类似装饰器的功能
– 资源管理
– 打开了资源需要关闭,例如文件对象、网络连接、数据库连接等
– 权限验证
– 在执行代码之前,做权限的验证,在__enter__中处理

##contextlib.contextmanager
– 它是一个装饰器实现上下文管理,装饰一个函数,而不用像类一样实现__enter__和__exit__方法。
– 对下面的函数有要求,必须有yield,也就是这个函数必须返回一个生成器,且只有yield一个值
– 如果业务逻辑简单可以使用函数加装饰器方式,如果业务复杂,用类的方式加__enter__和__exit__方法方便
###例子
import contextlib
import time
import datetime

@contextlib.contextmanager
def add(x,y):
start = datetime.datetime.now() #相当于__enter__
try:
yield x + y #enter的返回值
finally:
delta = (datetime.datetime.now() – start).total_seconds() #相当于__exit__
print(delta)

with add(4,5) as f:
time.sleep(2)
#raise Exception(‘Error’)
print(f)

##**functools.total_ordering装饰器**
– __lt__,__le__,__eq__,__gt__,__ge__ 是比较大小必须实现的方法,但是全部写完太麻烦,所以使用@functools.total_ordering简化代码
###例子
from functools import total_ordering
@total_ordering
class Person:
def __init__(self,age):
self._age = _age
@property
def age(self):
return self._age
def __eq__(self,other):
return self._age == other.age
def __lt__(self,other):
return self._age < other.age
p1 = Person(’20’)
p2 = Person(’30’)
if p1 >= p2:
print(‘p1 older’)
else:
print(‘p2 older’)

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

(0)
上一篇 2017-11-21 13:15
下一篇 2017-11-21 16:35

相关推荐

  • N22-第一周(作业)

    马哥教育网络班22期-第一周课程练习:   一.描述计算机的组成及其功能       计算机组成:CPU :包含控制器,运算器,寄存器,缓存。通过时序复用的方式来处理加工来自输入设备的指令或数据,协调各组件之间的工作       存储器(内存):编址存储单元阵列,用于暂时存放CP…

    Linux干货 2016-08-13
  • 马哥教育网络班21期-第6周课程练习

    第6周课程练习 请详细总结vim编辑器的使用并完成以下练习题   1、         复制/etc/rc.d/rc.sysinit文件至/tmp目录,将/tmp/rc.sysinit文件中的以至少一个空白字符开头的行的行首加#; # cp /etc/rc.d/rc.s…

    Linux干货 2016-08-30
  • 磁盘配额的操作步骤

    磁盘配额 操作步骤: 1、创建一个10G的分区 /dev/sdd1并将其格式化,挂载 2、如果是新硬盘便不存在同步问题。旧硬盘得使用命令partx  -a /dev/sdd1 3、临时创建挂载文件夹 /mnt/home    4、将/home/*  mv  到 /mnt/home 中,再将/dev/…

    Linux干货 2016-09-01
  • linux学习的环境构建

    俗话说磨刀不误砍柴工,所以在加入马哥linux培训班后第一件事情就是构建学习环境。在这里把一些心得分享给大家。 1:通过测试比较服务器选择运行ESXI6.0的虚拟机。刚开始准备采用微软的Hyper-v的,但是管理Hyper-v需要域环境(工作组环境下虽然也可以管理,但是配置复杂和安全性很低),额外的增加了系统开销所以果断放弃。 2:通过网络获得Esxi6.0…

    Linux干货 2016-02-28
  • 压缩与解压

        compress 命令使用“Lempress-Ziv”编码压缩数据文件。compress是个历史悠久的压缩程序,文件经它压缩后,其名称后面会多出”.Z”的扩展名。当要解压缩时,可执         &nbsp…

    2017-08-14
  • Bash编程之条件测试

    Bash 包含强大的编程功能,其中包括丰富的可测试文件类型和属性的函数,以及在多数编程语言中可以使用的算术和字符串比较函数。理解不同的测试并认识到 shell 还能把一些操作符解释成 shell 元字符,是学好Bash编程的重要一环。 一、测试命令 Bash中一条命令退出状态码可作为测试条件,执行成功返回0,代表布尔类型true;反之执行失败返回1-255之…

    Linux干货 2016-08-21