python学习笔记 day26 私有属性 和 property
1. 私有属性
class Student(): def __init__(self,name,password): self.name=name self.__password=password # 定义了一个私有属性 def get_password(self): # 定义了一个get_paasword的方法,里面是类内定义的私有属性 return self.__password def set_password(self,newpassword): # 修改私有属性的函数,需要传一个参数,也就是新的password值 self.__password=newpassword student=Student('璇璇',123) print(student.name) # 查看普通属性name print(student.get_password()) # 调用get_password方法来查看类内定义的私有属性(因为方法内返回了私有属性的值) student.set_password(234) # 使用set_password方法修改私有属性的值 print(student.get_password()) # 再次调用get_password方法查看私有属性的值(刚才被修改过)
运行结果:
2. 子类不能继承父类定义的私有方法
class Animal(): def __init__(self,name,weight): self.name=name self.__weight=weight # 定义一个私有属性 print(Animal.__dict__) # 可以查看Animal类的属性,方法等(这里的私有属性__weight其实真实:_Animal__weight) class Tiger(Animal): print(Animal.__weight) # 这里的私有属性__weight其实是指_Tiger__weight,所以是调不到的 tiger=Tiger('老虎',120)
运行结果:
其实如果真的使用暴力方法也是可以调到的~只是不建议这样做:就好比在类外面直接使用对象名._类名__私有属性名 直接可以拿到类内定义的私有属性一样~
自己写的,不知道这样算不算子类调用父类的私有属性~
class Animal(): def __init__(self,name,weight): self.name=name self.__weight=weight # 定义私有属性 class Tiger(Animal): def __init__(self,name,weight,kind): Animal.__init__(self,name,weight) # 在子类的同名方法中直接调用父类的同名方法 self.kind=kind def get_weight(self): return self._Animal__weight # 直接在子类中调用父类的私有属性 tiger=Tiger('老虎',123,'动物') print(tiger.get_weight())
运行结果:
总结:
只要是在类内定义的私有属性是不可以被子类调用的,只可以在类内调用(我上面的不太推荐,就好像不推荐在类外面使用对象名._类名__私有属性名 调用私有属性一样,尽管你能做到)
会用到私有属性的地方:
1. 隐藏其属性,不想被外部调用;
2.保护属性,不想被外部随意修改,比如可以定义一个set_password()方法,里面直接可以self.__password=new__password 但是在这一步之前可以判断传入的passsword是否符合要求,符合才修改,则海洋就可以进行约束,而不是在外面随意修改;
3. 保护属性,不想被子类继承;
3. property----内置函数(本质是装饰器)可以把一些应该当作属性来用的方法,“变”为属性;
property装饰的方法不能有参数!!
比如之前计算圆面积和周长的类:
from math import pi class Circle(): def __init__(self,r): self.r=r def perimeter(self): return 2*pi*self.r def area(self): return pi*self.r**2 c1=Circle(3) print(c1.perimeter()) # 查看圆周长 print(c1.area()) # 查看圆面积
但其实这里的area()方法和perimeer()方法看起来更应该是一个属性才对,因为方法一般都是和动作相关的,面积,周长这种名词,应该看起来更像是属性,所以我们可以借助property这个装饰器内置函数,来把方法变得像一个属性:
from math import pi class Circle(): def __init__(self,r): self.r=r @property # 把方法perimeter()方法当成属性来用 def perimeter(self): return 2*pi*self.r @property # 把方法area()当作属性来用 def area(self): return pi*self.r**2 c1=Circle(3) print(c1.perimeter) # 借助property就可以直接像调用属性的方式一样求调用方法perimeter()查看圆周长 print(c1.area) # 借助property就可以直接像调用属性的方式一样求调用方法area()查看圆面积
运行结果:
再来看一个计算BMI指数的例子,也是借助property来把一个看似属性的方法,变成更像属性,操作的时候就把被property装饰的方法当成属性调用就可以了~
class Cal_BMI(): def __init__(self,name,height,weight): self.name=name self.height=height self.weight=weight @property def BMI(self): return self.weight/(self.height**2) xuan=Cal_BMI('璇璇',1.63,43) print(xuan.BMI) # 由于BMI()方法使用property装饰,所以可以使用一个类似属性的形式去调用BMI()方法,使它看起来更像是一个属性
运行结果:
但是你会发现,即使把一个方法使用property去装饰,使它调用时看起来更像是一个属性,但是并不能像修改属性一样去修改该方法,毕竟人家只是调用起来橡属性,本质上还是一个方法!
xuan.BMI=20
当我们试图用修改普通属性的操作去修改一个被property装饰的方法时就会报错:
4.修改使用property装饰的类似属性的方法:
class Student(): def __init__(self,name,age,sex): self.__name=name # 定义一个私有属性 self.age=age self.sex=sex @property # 被property装饰的方法不可以传参数 def name(self): # 把 name方法使用property装饰,可以使用类似属性的方法去调用,使它看起来更像是属性 return self.__name @name.setter # 可以对刚才被property装饰的方法name进行修改,就好像是对普通属性的修改一样,这里的方法只可以传一个参数 def name(self,newname): self.__name=newname xuan=Student('xuanxuan',22,'女') print(xuan.name) # 其实是在调用name()方法,只是被property装饰了,可以像使用调用属性一样的方式去调用方法 xuan.name='璇璇' # 由于name被name.setter装饰了,所以可以像修改普通属性一样去修改方法 print(xuan.name) # 查看修改之后的
运行结果:
注意事项:
再举一个比较常见的例子:就是商品可能会随着节日等活动会有打折:我们就可以把price私有化,然后借助property把方法变得更像是一个属性
class Goods(): discount=0.5 # 折扣半价 def __init__(self,name,price): self.name=name self.__price=price # 把price私有化,然后后续使用property把price()方法变的更像是属性price 然后操作起来好像在操作属性proce @property def price(self): return self.__price * self.discount apple=Goods('苹果',6) print(apple.price)
运行结果:
后续如果折扣有变化,其实只需修改静态属性discount即可~其实这里的price()是一个方法,用来计算折扣后价格的方法,但是使用property装饰之后使它看起来更像是一个属性,当我们操作对象名.price 好像在操作一个属性,其实内部进行的是计算折扣后价格的方法price,,内部是有计算这一步骤的~
5.删除使用property装饰的类似属性的方法
如果想对使用property装饰过的看起来像属性的方法进行删除操作应该怎么实现呢?
class Student(): def __init__(self,name,age,sex): self.__name=name # 设置私有属性 self.age=age self.sex=sex @property # 被property装饰的方法不能有参数 def name(self): return self.__name @name.setter # 被name.setter装饰的方法也只能传一个参数,就是想要修改的新值 name.setter中的name必须与被property装饰的方法name()一样!(1) def name(self,newname): # 这里的方法名name也必须与被property装饰的方法名name一样(2) self.__name=newname @name.deleter # 被name.deleter装饰的方法也不能有参数,而且name.deleter中的name也必须与被property装饰的方法名一样(3) def name(self): # 这里的方法名也必须与被property装饰的方法名一样(4) del self.__name xuan=Student('xuanxuan',22,'女') print(xuan.name) # 其实是在调用方法name(),只是被property装饰了,可以像调用属性一样调用name方法 xuan.name='璇璇' # 可以对name()方法(被property装饰的看起来像属性的方法)像对普通属性的操作一样完成修改 print(xuan.name) # 可以打印修改后的 del xuan.name # 可以像删除属性一样删除方法name()是因为执行了name.deleter装饰的方法name() 里面实现了del self.__name try: print(xuan.name) # 其实name已经被删了,这里执行会报错 except Exception as error: print("name已经被删了",error)
运行结果: