python描述符魔术方法_Python基础教程(十) Python的面向对象编程之魔术方法

魔术方法:用__xxx___表示

__init__(self,p1,p2,...):

xxx

构造方法,实例化对象的时候会自动调用,一般用于初始化声明类的属性

例如:

class Person:

name=""

def __init__(self,name):

self.name=name

def sayname(self):

print(self.name)

zbp=Person("zbp")

zbp.sayname()

如何声明一个私有属性,在PHP中,所谓的私有属性就是只能在类内部使用的属性,不能在类之外使用

只要在属性名前添加"__",即可声明一个私有属性

如 __name="xxx"

或者self.__name="xxx"

但是呢其实这个私有变量是可以在外部调用的

访问 _类名__属性名 就可以

例如:

class Person:

__name="zbp"

zbp=Person()

print(zbp.name) #报错

print(zbp.__name) #报错

print(zbp._Person__name) #可以

#所以说py的私有变量其实是伪私有

构造方法只能返回None,不能返回其他类型

__del__(self) 析构方法

某对象的所有引用都被del之后,就会调用这个方法。

如:

class A:

def __del__(self):

print("析构函数")

a1=A()

a2=a1

a3=a2

del a1 #没输出

del a3 #没输出

del a2 #输出析构函数4字

算数魔术方法:

__add__(self,...) #对象相加时自动调用

__sub__(self,...) #...

__mul__(self,...)

__truediv__(self,..)

__repr__(self) #当调用对象时会调用,如

a=A()

a #调用

__str__(self) #当print对象时会调用

这两个方法都要返回字符串,否则报错

__getattr__(self,name) #当用户访问一个不存在的属性时调用

__getattribute__(self,name) #当用户访问类的一个属性时触发(在类内调用属性也会触发),无论这个属性是否存在

PS:__getattribute__的触发会先于__getattr__

__setattr__(self,name,value)#当设置一个属性时(无论是在类之内还是之外设置)触发,无论这个属性是否存在,调用这个方法返回的就是你访问的属性的属性值

__delattr__(self,name) #当干掉一个属性时触发

现在我有一个需求,Test类里面有一个属性是nickName

我的需求是,当我访问nickName属性,要输出nickName属性后加上abc这个字符

class Test:

nickName="zbp"

def __getattribute__(self,name):

newStr=super().__getattribute__(name) #super().__getattribute__(name)返回nickName的值,super()是object对象,是所有对象的基类

newStr+="abc"

return newStr

t=Test()

print(t.nickName)

描述符:(就是一个类)

就是将某种特殊类型的类(描述符)的实例指派给另一个类的属性

什么事特殊类型的类?

就是至少存在以下一个魔术方法的类:

__get__(self,instance,owner) 访问描述符对象时触发,要返回属性的值

__set__(self,instance,value) 在给描述符对象时触发,不返回任何内容

__delete__(self,instance)删除描述符对象时触发,不返回任何内容

现在写一个描述符:

class MyDecriptor:

def __get__(self,instance,owner):

print("getting",self,instance,owner)

def __set__(self,instance,value):

print("getting",self,instance,value)

def __delete__(self,instance)

print("getting",self,instance)

class Test:

x=MyDecriptor()

#这里将描述符的类实例化赋给Test的属性

test=Test()

test.x #触发描述符的__get__

#__get__里面的self是描述符对象,即x

#instance是test对象

#owner是Test这个类

test.x="zbp"#触发描述符的__set__

del test.x #触发描述符的__delete__

其实property()就是一个描述符

这里我们可以自己写一个描述符代替property的功能

class MyProperty:

def __init__(self,getAttr=None,setAttr=None,delAttr=None):

self.getAttr=getAttr#这里传进来的这3个参数的内容是方法,就是要将3个方法赋给描述符的变量

self.setAttr=setAttr#这么一来,MyProperty的这3个属性就变成了可以调用的方法

self.delAttr=delAttr

def __get__(self,instance,owner):

return self.getAttr(instance)

def __set__(self,instance,value):

self.setAttr(instance,value)

def __delete__(self,instance):

self.delAttr(instance)

class A():

__a=None #设置为私有的属性,必须调用方法来访问和设置该属性

def getA(self):

return self.__a

def setA(self,value):

self.__a=value

def delA(self):

del self.__a

x=MyProperty(getA,setA,delA)#将3个方法赋给描述符

定制容器:

什么是容器,就是能存放东西的变量,比如列表,字符串,字典,元组都是容器

如果希望定制的容器是不可变的话,只需定义__len__()和__getitem__()方法

如果是可变的,还要多定义__setitem__和__delitem__方法

__len__在len(对象)时触发

__getitem__在调用对象[key]时触发

__setitem__和__delitem__的触发以此类推

现在有一个需求,写一个自定义的列表,要求这个列表定义后不能改变,而且访问该列表的count属性能返回所有元素访问的次数

class MyList:

def __init__(self,*args):

self.list=list(args)

self.len=len(self.list)

#self.count={}.formkeys(range(self.len),0) #这句话可以代替下面的for循环

self.count={}

a=0

for i in self.list:

self.count[a]=0

a+=1

def __len__(self):

return self.len

def __getitem__(self,key):

if key<0 or key>self.len-1 :

return ""

self.count[key]+=1

return self.list[key]#不用担心这里会无限递归,self[key]才会无限递归

迭代器(迭代就是循环啦)

这里我要说一点:遍历列表,元组的时候,for i in xxx 中的i是序列的值

但是遍历字典的时候,for i in xxx中的i是字典的下标

xxx[i]才是他的值,就当是复习一下啦

介绍两个bif:

iter()/next()

str1="zbp"

it=iter(str1)

next(it)#z

next(it)#b

next(it)#p

next(it)#报错

for其实就是使用iter()和next()实现的

迭代器是一个具有__iter__()/__next__()魔术方法的类

__iter__()/__next__()

当循环一个对象的时候,就会自动调用这两个方法,__iter__()没有什么内容,直接return self即可

__next__()是每循环一次就调用一次

class addCount:

i=0

r=0

def __init__(self,s):#s是目标值

self.s=s

def __iter__(self):

return self

def __next__(self):

if(self.r>=self.s):

raise StopIteration#停止循环

else :

self.r+=self.i

self.i+=1

return self.r

a=addCount(1000)

for i in a:

print(i)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值