Day 22 封装 property
【封装】
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
【好处】
1. 将变化隔离;
2. 便于使用;
3. 提高复用性;
4. 提高安全性;
【封装原则】
1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。
私有变量和私有方法
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
# 私有的用途:
# 当一个方法不想被子类继承的时候
# 有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用
# java中的对比 # public 公有的 在类的内部可以使用,子类可以使用,外部可以使用 python中所有正常的名字 # protect 保护的 在类的内部可以使用,子类可以使用,外部不可以使用 python中没有 # private 私有的 只能在类的内部使用,子类和外部都不可以使用 python中的__名字
# 描述一个房子 #单价 #面积 class Room: def __init__(self,name,price,length,width,height): self.name = name self.price = price self.__length = length self.__width = width self.height = height @property def area(self): return self.__length * self.__width r = Room('peng',100,2,1,5) print(r.name) print(r.area)
# 一个私有的名字,在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到
# python对其的名字进行了修改:__类名__名字
# 只不过在类的外部调用:需要'_类名__名字'去使用
# 在类的内部可以正常的使用名字
class Person: # def __init__(self,name,pwd): # self.name = name # self.__pwd(pwd) # def __pwd(self,pwd): # # '12345' ---> ascii ---> 2175981070935 # self.my_secret_pwd = 2175981070935
# _A__N # 在类内 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字 # 私有的属性 class B: def __init__(self,name): self.__name = name def func(self): print('in func: %s'%self.__name) b = B('alex') print(b._B__name) b.func()
# 私有的方法 class C: def __wahaha(self): print('wahaha') def ADca(self): self.__wahaha() c= C() c._C__wahaha() c.ADca()
# 在类中,静态属性,方法,对象属性都可以变成私有的,只要在这些名字之前加上__
class D: def __func(self): #存储'_D__func' print('in func') class E(D): def __init__(self): # self.__func() 报错 self._D__func() #'_E__func' e = E()
》》》in func
#私有的名字不能被子类继承 class D: def __init__(self): self.__func() #_D__func def __func(self): print('in D') class E(D): def __func(self): print('in E') e = E()
》》》in D
class D: def __init__(self): self.__func() #_D__func def __func(self): print('in D') class E(D): def _D__func(self): print('in E') e = E()
>>>in E
# 私有的名字,在类内使用的时候,就是会变形成 _该类名__方法名
# 以此为例,没有双下划线会找到E中的func
# 但是有了双下划线,会在调用这个名字的类D 中直接找_D__func
class F:pass F.__name = 'alex' #不是在创建私有属性,只有在类的内部才关心下划线操作,变形只在类的内部发生,不会在外部发生 print(F.__name) print(F.__dict__)
alex
{'__dict__': <attribute '__dict__' of 'F' objects>, '__module__': '__main__', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'F' objects>, '__name': 'alex'}
class F: def ADCa(self): self.__name = 'alex' f = F() f.ADCa() # print(f.__name) #报错 print(f._F__name) 真正工作的时候不可以这么写,只是为了应付面试
Property
例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 成人的BMI数值: 过轻:低于18.5 正常:18.5-23.9 过重:24-27 肥胖:28-32 非常肥胖, 高于32 体质指数(BMI)=体重(kg)÷身高^2(m) EX:70kg÷(1.75×1.75)=22.86 class Person: def __init__(self,name,weight,height): self.name = name self.__weight =weight self.__height = height @property def BMI(self): return self.__weight /self.__height ** 2 kate = Person('kate',58,1.59) print(round(kate.BMI)) print(round(kate.BMI)) print(Person.__dict__) BMI': <property object at 0x102138958>,
BMI 是个名词
将一个方法伪装成一个属性
并不会让你的代码有什么逻辑上的提高
只是从调用者的角度上换了一种方式,使它看起来更合理
有了property装饰,bmi不能重名,也不能重新赋值,否则会报错,说白了就是只能看了,不能修改
@property能够将一个方法伪装成一个属性
从原来的对象名.方法名()变成了对象名.方法名
只是让代码变得更美观,并不会起到改变逻辑的作用
被property装饰的bmi仍然是一个方法 存在Person.__dict__
对象的__dict__ 中不会存储这个属性
在一个类加载的过程中,会先加载这个中的名字,包括被property装饰
在实例化对象的时候,python解释器会先到类的空间里看看有咩有这个被装饰的属性
如果有就不能再在自己的空间中创建这个属性了
# 将方法伪装成属性,方法中一般设计的就是一些计算过程
from math import pi class Circle: def __init__(self,r): self.r = r @property def area(self): return pi * self.r**2 @property def perimeter(self): return pi * 2* self.r p = Circle(10) print(round(p.area)) print(round(p.perimeter))
# 这样不能随意改姓名name,并且通过setname约束 class Person: def __init__(self,name): self.__name = name #私有的属性 @property def name(self): return self.__name def set_name(self,newname): if type(newname) is str: self.__name = newname else: print('您输入的姓名数据类型不合法') p = Person('alex') p.set_name('alex_sb') # p.set_name(123) 报错 print(p.name)
# 方法伪装成的属性的修改 class Person: def __init__(self,name): self.__name = name #私有的属性 @property def name(self): return self.__name @name.setter def name(self,newname): if type(newname) is str: print(newname) else: print('数据类型错误') p = Person('alex') print(p.name) #def name(self) p.name = 'SBBBBBB' #def name(self,newname): print(p.name) #def name(self) p.name = 123 print(p.name) #三个name必须一致
alex
SBBBBBB
alex
数据类型错误
#方法伪装成属性的删除
class Person: def __init__(self,name): self.__name = name @property def name(self): return self.__name @name.deleter def name(self): print('name 被删除') # @name.deleter # def name(self): # del self.__name #这个可以真正删除 p = Person('egon') print(p.name) del p.name #只相当于执行了被@name.deleter这个函数,并没有真正删除 print(p.name)
# @property--->func 将方法伪装成属性,只是看的事儿
# @func.setter ---->func 让伪装的属性进行赋值的时候用这个方法
# @func.deleter --->func 在执行del对象,func的时候调用这个方法,一般情况不用
# 商品的折扣
# 想看折后价格
class Goods:
def __init__(self,name,price,discount): self.name = name self.__price = price self.__discount = discount @property def price(self): return self.__price *self.__discount @price.setter def price(self,new_price): if type(new_price) is int or type(new_price) is float: self.__price = new_price else: print('您输入的数据类型错误') apple = Goods('apple',5,0.8) print(apple.price) # 修改苹果价格 apple.price = 8 print(apple.price)
店庆全场八折# 折扣结束 折扣变了 恢复折扣 class Product: __discount = 0.8 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price * Product.__discount @classmethod #不依赖对象的方法,就应该定义为类方法,类方法可以任意的操作类中的静态变量 def change_discount(cls,new_discount): # 类方法,可以直接被类调用,不需要默认传对象参数,只需要传一个类参数就可以了 cls.__discount = new_discount Product.change_discount(1) apple = Product('apple',5) banana = Product('banana',8) print(apple.price) print(banana.price)
#使用什么样的方法要看具体用到了哪些名称空间中的值
# 当一个方法要使用对象的属性时,就使用普通的方法
# 当一个方法要使用类中的静态属性时,就使用类方法
# 当一个方法既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法
# def login(): # user= input('user :') # if user == 'alex':print('success') # else :print('faild') # # login() class Student: def __init__(self,name):pass @staticmethod def login(a): # login就是一个类中的静态方法 静态方法没有默认参数 就当成普通的函数使用即可 user = input('user :') if user == 'alex': print('success') else: print('faild') Student.login(1)
class A: __role = 'CHINA' @classmethod def show_role(cls): print(cls.__role) @staticmethod def get_role(): return A.__role @property def role(self): return self.__role a = A() print(a.role) print(a.get_role()) a.show_role()
CHINA
CHINA
CHINA