封装、property装饰器
封装分为3种情况:封装对象的属性、封装类的属性、封装方法。
封装对象的属性:(在属性名前加双下划线__)
class Person: def __init__(self,height,weight,name,sex): self.__height = height #私有对象属性:不在外面调它 self.__weight = weight self.__name = name self.__sex = sex def bmi(self): return self.__weight / self.__height ** 2 def tell_height(self): print(self.__height) def tell_weight(self): return self.__weight def set_weight(self,new_weight): if new_weight > 20: self.__weight = new_weight egg = Person(1.7,125,'egon',None) egg.tell_height()#在类内调 print(egg.__dict__)#查看类内的私有属性 print(egg._Person__height)#在类外调用
通过私有属性后,我们可以更好的确保属性数值不会随意修改。
封装属性我们可以在set——weight里约束属性值得更改
class Person: def __init__(self,height,weight,name,sex): self.__height = height #私有对象属性:不在外面调它 self.__weight = weight self.__name = name self.__sex = sex def bmi(self): return self.__weight / self.__height ** 2 def tell_height(self): print(self.__height) def tell_weight(self): return self.__weight def set_weight(self,new_weight): if new_weight > 20: self.__weight = new_weight egg = Person(1.7,125,'egon',None) egg.tell_height()#在类内调 # print(egg.__dict__)#查看类内的私有属性 print(egg._Person__height)#在类外调用 egg.set_weight(105) print(egg.tell_weight()) #私有属性: # 在本类内就可以正常调用 # 在本类外就必须_类名__属性名调用,(不建议你调)
封装类的属性
class Goods: __discount = 0.8 #类的私有属性 def __init__(self,name,price): self.name = name self.price = price def goods_price(self): return self.price * Goods.__discount banana = Goods('banana',2) print(banana.goods_price())#类内调用 # print(Goods.__dict__)#查看类的私有属性 print(Goods._Goods__discount)#在类外调用私有属性
封装对象的方法
class Foo: def __init__(self,height,weight): self.height = height self.weight = weight def tell_bmi(self): #体重/身高的平方 return self.weight / self.__heightpow() def __heightpow(self): #私有方法 return self.height * self.height egon = Foo(1.7,125) print(egon.tell_bmi()) print(Foo.__dict__) print(egon._Foo__heightpow()) #类外调用方法 #私有的:类属性 对象属性 方法 #变成私有的 :__名字 #在类内都是照常使用 #在类外部就变形称为:_类名__名字 #定义私有~的原因 #不让外部的人瞎调,不让子类继承
封装的进阶
通过property装饰器把一个方法变成一个属性用
from math import pi class Circle: def __init__(self,radius): self.radius = radius @property #area = property(area) def area(self): return pi*self.radius*self.radius @property def perimeter(self): return 2*pi*self.radius c = Circle(10) print(c.area) print(c.perimeter)
我们调用area方法和perimeter方法就像调用属性一样
上个牛逼的代码(缓存网页的,用面向对象的方法)
from urllib.request import urlopen class Web_page: def __init__(self,url): self.url = url self.__content = None#私有对象属性 @property def content(self): #content 内容,相当于一个属性 if self.__content: #做了一个什么转换 _Web_page__content return self.__content else: self.__content = urlopen(self.url).read().decode(encoding='utf-8') #做缓存 return self.__content mypage = Web_page('http://www.baidu.com') print(mypage.content) print(mypage.content)
计算传入数据的值
#计算传入的数据的值 class Num: def __init__(self,*args): print(args) if len(args) == 1 and (type(args[0]) is list or type(args[0]) is tuple): self.members = args[0] else: self.members = args @property def sum(self): return sum(self.members) @property def average(self): return self.sum/len(self.members) @property def min(self): return min(self.members) @property def max(self): return max(self.members) nums = Num([1,2,3]) print(nums.sum) # print(nums.average) # print(nums.min) # print(nums.max) # num2 = Num(4,5,6) # print(num2.sum) # print(num2.average) # print(num2.min) # print(num2.max)
property装饰器(property、set、del方法)
class Goods: __discount = 0.8 #类的私有属性 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): new_price=self.__price * Goods.__discount return new_price @price.setter def price(self,new_price): if type(new_price) is int: self.__price = new_price @price.deleter def price(self): del self.__price apple = Goods('apple',10) print(apple.price) apple.price = 20 print(apple.price)
总结
#@property把一个类中的方法 伪装成属性 #obj.func() #obj.func -->属性 #因为属性不能被修改 #@funcname.setter,来修改 #obj.func = new_value 调用的是被@funcname.setter装饰器装饰的方法 #被@property装饰的方法名必须和被@funcname.setter装饰的方法同名 #@funcname.deleter #在执行del obj.func 的时候会调用被这个装饰器装饰的方法(同名)