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