面向对象魔术方法

##**特殊属性**
– __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

相关推荐

  • linux权限管理

    linux文件权限    文件的属性和权限的设置对于linux系统来说是相当重要的,如果对这一块的知识没有一个深入的了解,你的系统就有可能有很大的危险。那么首先我们来看一看文件的属性所对应的都是什么意思吧。 上图第一个字符是d,他代表了文件的类型,d的意思就是目录文件,那么除了目录文件还有什么文件呢?    …

    Linux干货 2016-08-04
  • 安全和加密与创建签名证书

    安全和加密:NIST定义的安全属性:(美国国家标准与技术研究院)保密性:        数据保密性        隐私性完整性:不可篡改        数据完整性        系统完整性高可用性: …

    Linux干货 2017-04-11
  • Linux系统上获取命令的帮助信息

    获取命令的使用帮助: 内部命令:help COMMAND   #针对内检命令 外部命令: (1) 命令自带简要格式的使用帮助      COMMAND –help (2) 使用手册:manual  [root@localhost /]# ls /usr/share/man   #记住这个…

    Linux干货 2016-08-15
  • 第三周

    作业

    2017-12-15
  • linux 启动文件 /etc/fstab 文件删除 无法开机 修复的方法

    /etc/fstab文件删除系统自检无法挂载 无法启动 按照提示进入命令行  手动写/etc/fstab,如无内核文件  无grub  就缺啥补啥 fdisk    -l 查看当前分区  blkid    查看分区文件系统的卷标 手动挂载 …

    Linux干货 2016-09-13
  • 带你走进PI的世界-Raspbian Pi上实现LAMP

     初识   Raspbian PI                   前段时间,出于兴趣,入手一个树莓派(Raspbian PI…

    Linux干货 2016-01-05