面向对象魔术方法

##**特殊属性**
– __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)
miraclermiracler
上一篇 2017-11-21 13:15
下一篇 2017-11-21 16:35

相关推荐

  • 马哥教育网络班22期第二周课程练习1-未闻花名

    1、Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touch 创建文件 mv 移动文件 rm 删除文件 rmdir 删除目录 1.1 pwd命令 该命令的英文解释为print working directory(打…

    Linux干货 2016-08-22
  • 细数Linux发行版

    什么是Linux 广义上讲:Linux内核+应用程序狭义上讲:Linux内核  > Linux内核指的是我们通常所说的Kernel,主要用于负责系统调用、进程管理、内存管理、文件系统管理等功能。  应用程序指的是由GNU组织提供的开源的、通用的应用程序,如gcc、glibc、vi等。 我们平常所说的Linux,通常指广义层面上的Li…

    Linux干货 2017-08-30
  • AWK——文本处理三剑客

    GNU awk ·文本处理三工具:grep,sed,awk          grep,egrep,fgrep:文本过滤工具:pattern          sed:行编辑器  &nbsp…

    Linux干货 2016-09-20
  • ansible配置详解

    概述     ansible是一款无需在被管理主机上安装客户端,基于SSH对多台目标主机进行同时操作的轻量级的管理软件,借助各个内部的功能模块,实现了批量系统配置、批量程序部署、批量运行命令等功能。本篇就介绍一些关于ansible的基础配置相关的内容,具体包括:     1、an…

    Linux干货 2016-11-05
  • 文本查看类命令

    文本查看相关的命令:1.  cat – 串连文件,并以标准输出显示语法:cat [OPTION]… [FILE]… 常用选项 选项 | 含义—— | ——-n | 在显示文件内容时打印行号示例:~]# cat -n /etc/rc.d/init.d/functions显示/e…

    2017-09-07
  • 分布式存储 Mogilefs 部署

    MogileFS是一个开源的分布式存储的解决方案,主要工作组件由三部分组成:Tracker节点:生成映射表存储于DB,并用于接收客户端请求,通过查询数据库对客户端提供后端所存储的真实文件位置DB节点:主要存储数据的元数据信息,可以理解为客户端来获取数据文件时提供的Key和真实存在存储里面的文件名的对照表Storage节点:用于存储文件的节点。工作流程,tra…

    2017-03-04