Python day 22面向对象之封装
封装
面向对象三大特性:继承 多态 封装
封装 :
广义上的:把一堆东西装在一个容器里
狭义上的 :会对一种现象起一个专门属于它的名字
函数和属性装到了一个非全局的命名空间 —— 封装
1 # class A: 2 # __N = 'aaa' # 静态变量 3 # 4 # print(A.__N) 5 6 # python 7 # pulic 公有的 8 # private 私有的 9 10 # java完全面向对象的语言 11 # public 公有的 12 # protect 保护的 13 # private 私有的
定义一个私有的名字 : 就是在私有的名气前面加两条下划线 __N = 'aaa'
所谓私有,就是不能在类的外面去引用它
1 class A: 2 # __N = 'aaa' # 静态变量 3 # def func(self): 4 # print(A.__N) # 在类的内部使用正常 5 # 6 # a = A() 7 # a.func() 8 # print(A.__N) # 在类的外部直接使用 报错
1 # class A: 2 # __N = 'aaa' # 静态变量 3 # def func(self): 4 # print(A.__N) # 在类的内部使用正常 5 # 6 # print(A.__dict__) 7 # print(A._A__N) # python就是把__名字当成私有的语法
一个私有的名字 在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到。
python对其的名字进行了修改: _类名__名字
只不过在类的外部调用 :需要“_类名__名字”去使用
在类的内部可以正常的使用名字
_A__N
在类内 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字、
1 私有的属性 2 # class B: 3 # def __init__(self,name): 4 # self.__name = name 5 # def func(self): 6 # print('in func : %s'%self.__name) 7 # b = B('alex') 8 # # print(b._B__name) 9 # b.func() 10 11 # 私有的方法 12 # class C: 13 # def __wahaha(self): 14 # print('wahaha') 15 # def ADCa(self): 16 # self.__wahaha() 17 # c = C() 18 # # c._C__wahaha() 19 # c.ADCa()
在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字之前加上__
1 class D: 2 # def __func(self): # '_D__func' 3 # print('in func') 4 # 5 # class E(D): 6 # def __init__(self): 7 # self.__func() # '_E__func' 8 # e = E()
私有的名字不能被子类继承
1 class D: 2 # def __init__(self): 3 # self.__func() 4 # def __func(self): 5 # print('in D') 6 # 7 # class E(D): 8 # def __func(self): 9 # print('in E') 10 # e = E()
私有的名字,在类内使用的时候,就是会变形成_该类名__方法名
以此为例 :没有双下换线会先找E中的func
但是有了双下划线,会在调用这个名字的类D中直接找_D__func
1 class F: 2 pass 3 F.__name = 'alex' # 不是在创建私有属性 4 print(F.__name) 5 print(F.__dict__) 6 变形只在类的内部发生 7 8 class F: 9 def ADCa(self): 10 self.__name = 'alex' # _F__name 11 12 f = F() 13 f.ADCa() 14 print(f._F__name)
java中的对比
public 公有的 在类的内部可以使用,子类可以使用,外部可以使用 python中所有正常的名字
protect 保护的 在类的内部可以使用,子类可以使用,外部不可以使用 python中没有
private 私有的 只能在类的内部使用,子类和外部都不可以使用 python中的__名字
私有的用法
当一个方法不想被子类继承的时候
有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用
1 # 描述一个房子 2 # 单价 3 # 面积 4 # 长宽高 5 # class Room: 6 # def __init__(self,name,price,length,width,height): 7 # self.name = name 8 # self.price = price 9 # self.__length = length 10 # self.__width = width 11 # self.__height = height 12 # 13 # def area(self): 14 # return self.__length*self.__width 15 16 # r = Room('鹏鹏',100,2,1,0.5) 17 # print(r.name) 18 # print(r.price) 19 # print(r.area()) 20 21 # class Person: 22 # def __init__(self,name,pwd): 23 # self.name = name 24 # self.__pwd(pwd) 25 # def __pwd(self,pwd): 26 # # '12345' ---> ascii ---> 2175981070935 27 # self.my_secret_pwd = 2175981070935
property方法
1 # 人体BMI指数 2 # 体质指数(BMI)=体重(kg)÷身高^2(m) 3 # 写一个类 描述人体BMI指数 4 5 class Person: 6 def __init__(self,name,weight,height): 7 self.name = name 8 self.__height = height 9 self.__weight = weight 10 # self.bmi = self.__weight / self.__height ** 2 11 # self.bmi = self.cal_BMI() 12 13 def cal_BMI(self): 14 return self.__weight / self.__height ** 2 15 16 @property 17 def bmi(self): 18 return self.__weight / self.__height ** 2 19 p = Person('大表哥',92,1.85) 20 # print(p.cal_BMI()) 21 # p.cal_BMI() # bmi是一个名词 22 # print(p.bmi) # bmi是一个名词 23 # p._Person__weight = 90 24 # print(p.bmi)
将一个方法伪装成一个属性
并不会让你的代码有什么逻辑上的提高
只是从调用者的角度上换了一种方式,使之看起来更合理
1 单纯的在init中计算 2 # class Person: 3 # def __init__(self,name,weight,height): 4 # self.name = name 5 # self.__height = height 6 # self.__weight = weight 7 # self.bmi = self.__weight / self.__height ** 2 8 # 9 # p = Person('大表哥',92,1.85) # 10 # print(p.bmi) # bmi是一个名词 11 # p._Person__weight = 90 # 3天 12 # print(p.bmi) 13 14 # class Person: 15 # def __init__(self,name,weight,height): 16 # self.name = name 17 # self.__height = height 18 # self.__weight = weight 19 # @property 20 # def bmi(self): 21 # return self.__weight / self.__height ** 2 22 # 23 # p = Person('大表哥',92,1.85) 24 # print(p.bmi) 25 # p._Person__weight = 90 26 # print(p.bmi)
@property 能够将一个方法伪装成一个属性
从原来的的对象名.方法名(),变成了对象名.方法名
只是让代码变的更美观
1 如果有重名的名字 2 # class Person: 3 # def __init__(self,name,weight,height): 4 # self.name = name 5 # self.__height = height 6 # self.__weight = weight 7 # @property 8 # def bmi(self): 9 # return self.__weight / self.__height ** 2 10 # print(Person.__dict__) 11 # p = Person('大表哥',92,1.85) 12 # print(p.__dict__) 13 # print(p.bmi) # 对这个属性 只能看了
被property装饰的bmi仍然是一个方法 存在Person.__dict__
对象的.__dict__中不会存储这个属性
在一个类加载的过程中,会先加载这个中的名字,包括被property装饰的
在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性,
如果有就不能再在自己对象的空间中创建这个属性了
1 # 圆形类 2 # 半径 面积 周长 3 # from math import pi 4 # class Circle: 5 # def __init__(self,r): 6 # self.r = r 7 # def cal_area(self): 8 # return self.r**2*pi 9 # def cal_perimeter(self): 10 # return 2*pi*self.r 11 # c = Circle(10) 12 # print(c.cal_area()) 13 # print(c.cal_perimeter()) 14 15 # 将方法伪装成属性,方法中一般涉及的都是一些计算过程 16 # from math import pi 17 # class Circle: 18 # def __init__(self,r): 19 # self.r = r 20 # @property 21 # def area(self): 22 # return self.r**2*pi 23 # 24 # @property 25 # def perimeter(self): 26 # return 2*pi*self.r 27 # c = Circle(10) 28 # print(c.area) 29 # print(c.perimeter) 30 # c.r = 15 31 # print(c.area) 32 # print(c.perimeter) 33 34 # __name setter deleter 35 # class Person0: 36 # def __init__(self,name): 37 # self.name = name 38 # 39 # p = Person0('alex') 40 # print(p.name) 41 # p.name = 'sb' 42 # p.name = 123 43 44 # class Person: 45 # def __init__(self,name): 46 # self.__name = name # 私有的属性了 47 # @property 48 # def name(self): 49 # return self.__name 50 # 51 # def set_name(self,new_name): 52 # if type(new_name) is str: 53 # self.__name = new_name 54 # else: 55 # print('您提供的姓名数据类型不合法') 56 # 57 # p = Person('alex') 58 # print(p.name)
1 和直接定义name属性有什么区别??? 2 p.set_name('alex_sb') 3 print(p.name) 4 p.set_name(123) 5 print(p.name)
1 方法伪装成的属性的修改 2 # class Person: 3 # def __init__(self,n): 4 # self.__name = n # 私有的属性了 5 # @property 6 # def name(self): 7 # return self.__name 8 # 9 # @name.setter # 重要程度 *** 10 # def name(self,new_name): 11 # if type(new_name) is str: 12 # self.__name = new_name 13 # else: 14 # print('您提供的姓名数据类型不合法') 15 # 16 # p = Person('alex') 17 # print(p.name) #def name(self): 18 # p.name = 'alex_sb' #def name(self,new_name): 19 # print(p.name) #def name(self): 20 # p.name = 123 #def name(self,new_name): 21 # print(p.name) #def name(self): 22 23 # 方法伪装成的属性的删除 24 class Person: 25 def __init__(self,n): 26 self.__name = n # 私有的属性了 27 @property # 重要程度 **** 28 def name(self): 29 return self.__name 30 # @name.deleter 31 # def name(self): 32 # print('name 被删除了') 33 # @name.deleter # 重要程度* 34 # def name(self): 35 # del self.__name 36 37 # p = Person('alex') 38 # print(p.name) 39 # del p.name # 只是执行了被@name.deleter装饰的函数 40 # print(p.name) 41 42 #@property --> func 将方法伪装成属性,只观看的事儿 43 #@func.setter --> func 对伪装的属性进行赋值的时候调用这个方法 一般情况下用来做修改 44 #@func.deleter --> func 在执行del 对象.func的时候调用这个方法 一般情况下用来做删除 基本不用 45 46 # 商品的 折扣 47 # 有一个商品 : 原价 折扣 48 # 当我要查看价格的时候 我想看折后价 49 # class Goods: 50 # def __init__(self,name,origin_price,discount): 51 # self.name = name 52 # self.__price = origin_price 53 # self.__discount = discount 54 # 55 # @property 56 # def price(self): 57 # return self.__price * self.__discount 58 # @price.setter 59 # def price(self,new_price): 60 # if type(new_price) is int or type(new_price) is float: 61 # self.__price = new_price 62 # apple = Goods('apple',5,0.8) 63 # print(apple.price) 64 # # 修改苹果的原价 65 # apple.price = 8 66 # print(apple.price)
将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性
classmethod和staticmethod
1 # 店庆 全场八折 2 class Goods: 3 __discount = 0.8 4 def __init__(self,name,origin_price): 5 self.name = name 6 self.__price = origin_price 7 8 @property 9 def price(self): 10 return self.__price * Goods.__discount 11 12 @classmethod 13 def change_discount(cls,new_discount): # 类方法 可以直接被类调用 不需要默认传对象参数 只需要传一个类参数就可以了 14 cls.__discount = new_discount 15 16 Goods.change_discount(1) # 不依赖对象的方法 就应该定义成类方法 类方法可以任意的操作类中的静态变量 17 apple = Goods('apple',5) 18 banana = Goods('banana',8) 19 print(apple.price) 20 print(banana.price) 21 22 # 折扣变了 店庆结束 恢复折扣 23 # apple.change_discount(1) # 如果要改变折扣 是全场的事情 不牵扯到一个具体的物品 所以不应该使用对象来调用这个方法 24 # print(apple.price) 25 # print(banana.price)
staticmethod
当一个方法要使用对象的属性时 就是用普通的方法
当一个方法要使用类中的静态属性时 就是用类方法
当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法
1 # def login(): 2 # user= input('user :') 3 # if user == 'alex':print('success') 4 # else :print('faild') 5 # 6 # login() 7 class Student: 8 def __init__(self,name):pass 9 10 @staticmethod 11 def login(a): # login就是一个类中的静态方法 静态方法没有默认参数 就当成普通的函数使用即可 12 user = input('user :') 13 if user == 'alex': 14 print('success') 15 else: 16 print('faild') 17 18 Student.login(1)
完全面向对象编程
先登录 后 实例化
还没有一个具体的对象的时候 就要执行login方法
使用什么样的方法要看具体用到了哪些名称空间中的变量
当一个方法要使用对象的属性时 就是用普通的方法
当一个方法要使用类中的静态属性时 就是用类方法
当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法








浙公网安备 33010602011771号