python魔术方法_Python魔术方法

本文详细介绍了Python的魔术方法,包括创建、初始化与销毁、hash、bool、可视化、运算符重载、容器和大小、可调用对象、上下文管理以及反射等关键概念。通过示例解释了如何实现这些魔术方法,如`__hash__`用于实现哈希、`__repr__`和`__str__`控制对象的字符串表示,以及`__enter__`和`__exit__`在上下文管理中的作用。此外,还讨论了动态增加属性的方法,如`getattr`、`setattr`和`hasattr`。
摘要由CSDN通过智能技术生成

分类:

1.创建,初始化与销毁 __init__.__del__

类实例化调用__init__;当运行结束,.del 标识符,引用计数为0的时候调用__del__

2.hash

1.内建函数hash()调用的返回值,返回一个整数,如果定义这个方法该类的实例可hash;

2.hash是为了提供set,dict的key,hash可以冲突,冲突的时候用__eq__比较内容,实现去重

3.类一般都是可以hash,由于继承基类的属性,但是没有事项__hash__,我们认为不可以hash

4.list bytearray 内部用 __hash__ = None 实现不可以hash

classPoint:def __init__(self,x,y):

self.x=x

self.y=ydef __hash__(self): #return 就是一个元祖,想要返回对象 Point(self.x,self,y)

returnhash((self.x,self.y))def __eq__(self,other): #运算符重载 p1 == p2,判断对象是否相等,返回bool

return (self.x,self.y) ==(other.x,other.y)

#     return self.x ==other.x and self.y == other.ydef __repr__(self):return 'Point.x={},Point.y={}'.format(self.x,self.y)

3.bool

1.内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回bool,没有定义__bool__(),就找__len__()的长度,非0为真,如果__len__()也没有定义,所有实例都返回真

classA:def __len__(self):return 100

__hash__ =NoneifA():print("real a")

bool(A)

bool(A())

4.可视化

1.__repr__内建函数repr()对一个对象获取字符串表达,调用魔术方法返回字符串表达,如果没有定义,就直接返回object的定义就式显示内存的地址信息

2.__str__,str()函数,内建函数format(),print()函数调用,需要返回对象的字符串表达,如果没有定义,就去调用__repr__方法返回字符串表达,如果__repr__也没有定义,就直接返回对象的内存地址信息

3.__bytes__,bytes()函数调用,返回一个对象的bytes表达,返回bytes对象

5.运算符重载

1.比较运算符:lt,le,eq,gt,ge,ne -->[ ,>= ,!=]

2.算数运算符:add,sub,mul,truediv,mod,floordiv,pow,divmod -->[+-*/% // ** divmod]

3.iadd,isub,imul,itruediv,imod,ifloordiv,ipow --> [+=,-=,*=,/=,%=,//=,**=]

classPoint:def __init__(self,x,y):

self.x=x

self.y=ydef __sub__(self,other):return Point(self.x-other.x,self.y-other.y)def __add__(self,other):return Point(self.x+other.x,self.y+other.y)def __repr__(self):return ''.format(self.x,self.y)

6.容器和大小

1.__len__:内建函数len(),返回对象长度,

2.__iter__:迭代容器的时候,调用,返回一个新的迭代对象(没有这个方法是instance(cart,Iterable)返回false,当for i in cart:调用__iter__)

3.__contains__:in成员运算符,没有实现就掉用__iter__方法遍历

4.__getitem__:实现self[key]访问,序列对象,key接受整数位索引,或者切片,对于set,dict,key为hashable,key不存在引发保存,索引访问

5.__setitem__:是设置值的方法,索引赋值6.__missing__:字典或其子类使用__getitem__调用时,key不存在执行该方法

classCart:def __init__(self):

self.items=[]defadd(self,value):

self.items.append(value)def __len__(self):returnlen(self.items)def __iter__(self):returniter(self.items)

#yield from self.itemsdef __getitem__(self, item):returnself.items[item]def __setitem__(self, key, value):

self.items[key]=valuedef __str__(self):returnstr(self.items)def __add__(self, other):

self.items.append(other)returnself

cart=Cart()print(cart)

cart.add(1)

cart.add(2)

cart.add(3)print(cart+4+5+6) #链式变成实现加法

print(cart.__add__(17).__add__(18)

7.可调用对象

1.Pyhon一切皆对象,函数也不例外

2.__call__:类中定义一个该方法,实例就可以像函数一样调用

3.可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用

4.要实现类实例的函数调用可以把函数调用写在__call__()内

5.可调用对象可以实现类装饰器; 见下面例子

classPoint:def __init__(self,x,y):

self.x=x

self.y=ydef __call__(self,*args,**kwargs):return "".format(self.x,self.y)

p= Point(4,5)

p()

classAdder:def __call__(self,*args):

ret=0for x inargs:

ret+=x

self.ret=retreturnret

p=Adder()

p(10,10)

p.ret

斐波数列用可调用方式并包装成容器实现

classFib:def __init__(self):

self.item=[0,1,1]def __call__(self,num):if num

self.item.append(self.item[i-1]+self.item[i-2])returnself.itemdef __iter__(self):returniter(self.item)def __len__(self):returnlen(self.item)def __getitem__(self,key):returnself.item[key]

fib=Fib()for i infib:print(i)

len(fib)

fib[2]

classFib:def __init__(self):

self.item=[0,1,1]def __call__(self,num):#num为形参,fib()先调用call,return在调用getitem魔术方法

returnself[num]def __iter__(self):returniter(self.item)def __len__(self):returnlen(self.item)def __getitem__(self,num): #这个num为实参,后调用getitem

if num

self.item.append(self.item[i-1]+self.item[i-2])#return self.item[num]

def __str__(self):returnstr(self.item)__repr__=__str__fib=Fib()

fib(5)print(fib(5))

importtimefrom datetime importdatetimefrom functools importwraps,update_wrapperclassTimeie:"""this is Timeit"""

def __init__(self,fn):

self.fn=fn#update_wrapper(self,fn)

wraps(fn)(self) #wrapper = wraps(fn)(wrapper)

def __call__(self,x,y):

self.start=datetime.now()

ret=self.fn(x,y)

delta= (datetime.now()-self.start).total_seconds()print(delta)returnret

@Timeie#add = Timeit(add)

defadd(x,y):"""this is add"""time.sleep(2)return x+y

add(4,5)

8.上下文管理

1.当一个对象同时实现了__enter__()和__exit__()方法,它就属于上下文管理的对象

2.__enter__:进入与次相关的上下文,如果存在该方法,with语法就会把该方法返回

__enter__方法返回值就是上下文中使用的对象,with语法会把他的返回值赋值给as子句的变量

3.__exit__:退出与此对象相关的上下文;方法返回一个等效的True值,压制异常,否则继续抛出异常

4.应用场景:增强功能,资源管理,权限验证(在执行代码前,做权限验证,在__enter__中处理)

5.contextlib库,@contextlib.contextmanager ;用来装饰函数,函数必须返回生成器,只有一个yield值;增加try保证exit执行

try:

yield 5 #yield之前当作enter,之后当作exit,;yield值当作enter返回值

finally:

print('exit')

classPoint:def __init__(self):print('init')def __enter__(self):print('enter')

return selfdef __exit__(self, exc_type, exc_val, exc_tb):print('exit')

with Point() as f:#output init-->enter-->f-->exit

print('f')

实例化对象的时候,并不会调用enter,进入with语句块的时候调用_enter__方法,然后执行语句体,

最后离开with语句快的时候调用__exit__方法,如果with语句块发生异常,enter,exit照样执行,上下文管理最安全

classPoint:def __init__(self):print('init')def __enter__(self):print('enter')returnselfdef __exit__(self, exc_type, exc_val, exc_tb):print('exit')print(exc_type,exc_val,exc_tb)return0

p=Point()

with p as f:#output init-->enter-->f-->exit

raise Exception("new erroe")print('f')

importtimefrom datetime importdatetimedefadd(x,y):

time.sleep(2)return x+yclassTimeit:def __init__(self,fn):

self.fn=fn

def __enter__(self):

self.start=datetime.now()returnselfdef __exit__(self, exc_type, exc_val, exc_tb):

delta= (datetime.now()-self.start).total_seconds()print(delta)def __call__(self,x,y):returnself.fn(x,y)

p=Timeit(add)print(p) #<__main__.timeit object at>

print(Timeit(add)) #<__main__.timeit object at>

with p as f:#with Timeit(add) as f ;print-->false print(p==f) f(5,6)

9.反射:动态增加属性

1.getattr(object,name,default) 通过name返回object的属性值,当属性值不存在的时候,将使用default返回,如果没有default,抛出异常,name必须为字符串

2.setattr(object,name,value) object的属性存在,则覆盖,不存在新增

3.hasattr(object,name) 判断对象是否有这个名字的属性,name必须为字符串

classDispatcher:def __init__(self):

self.run()defcmd1(self):print('i am cmd1')defcmd2(self):print("i am cmd2")defrun(self):whileTrue:

cmd= input('please input a command').strip()if cmd == 'quit':breakgetattr(self,cmd,lambda:print('unkown{}'.format(cmd)))()

1.__getattr__():一般属性会按照继承关系找,如果找不到,就会执行__getattr__()方法,没有抛错

2.__setattr__():实例通过.设置属性,如同self.x = x 就会调用__setattr__(),属性要加到__dict__就要自己完成

3.__delattr__():可以阻止通过实例删除属性的操作,但是通过类依然可以删除属性

4.__getattribute__():实例的所有属性访问都会调用__getattribute方法,它阻止了属性的查找,该方法应该返回计算后的值,或者抛出个异常;return的值作为属性的查找结果,如果抛错,调用__getattr__表示属性没有找到

classBase:

n=0classPoint(Base):

z= 6

def __init__(self,x,y):print('init')

self.x=xprint('init2')

self.y=ydefshow(self):print(self.x,self.y)def __getattr__(self,item):

setattr(self,item,0)#getattr(self,item)产生递归#return 'missing {}'.format(item)

def __setattr__(self,key,value): #self.x 就会调用这个函数,如果不操作__dict__,就是空字典

print('setattr')print("setattr {}={}".format(key,value))

self.__dict__[key] =value#setattr(self,key,value)产生递归#getattr(self,key,value)产生递归

def __delattr__(self,item):print('can not del {}'.format(item))

p1= Point(3,4)

p1.__dict__p1.aa=100 #aa:100

p1.t #t:0

del p1.x #output can not del x

del Point.z#删除类的属性

classBase:

n=0classPoint(Base):

z= 6

def __init__(self,x,y):print('init')

self.x=x

self.y=ydef __getattr__(self,item):return 'missing{}'.format(item)def __getattribute__(self,item):#所有实例的随性都从调用这个函数开始

print('getattribute')return object.__getattribute__(self,item)

属性实例查找顺序:

实例调用__getattribute__()-->instance.__dict__-->instance.__class__.__dict__-->继承德祖先类直到object-->调用__getattr__()

10.描述器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值