更多优质内容
请关注公众号

Python基础教程(十) Python的面向对象编程之魔术方法-阿沛IT博客

正文内容

Python基础教程(十) Python的面向对象编程之魔术方法

栏目:Python 系列:Python基础教程系列 发布时间:2019-10-30 16:55 浏览量:3088

魔术方法:用__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)

 




更多内容请关注微信公众号
zbpblog微信公众号

如果您需要转载,可以点击下方按钮可以进行复制粘贴;本站博客文章为原创,请转载时注明以下信息

张柏沛IT技术博客 > Python基础教程(十) Python的面向对象编程之魔术方法

热门推荐
推荐新闻