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 私有的
View Code
定义一个私有的名字 : 就是在私有的名气前面加两条下划线 __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)   # 在类的外部直接使用 报错
View Code
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就是把__名字当成私有的语法
View Code
一个私有的名字 在存储的过程中仍然会出现在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()
View Code
在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字之前加上__
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()
View Code
私有的名字不能被子类继承
 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()
View Code
私有的名字,在类内使用的时候,就是会变形成_该类名__方法名
以此为例 :没有双下换线会先找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)
View Code
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
View Code

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)
View Code
将一个方法伪装成一个属性
并不会让你的代码有什么逻辑上的提高
只是从调用者的角度上换了一种方式,使之看起来更合理
 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)
View Code
@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)   # 对这个属性 只能看了
View Code
被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)
View Code
1 和直接定义name属性有什么区别???
2 p.set_name('alex_sb')
3 print(p.name)
4 p.set_name(123)
5 print(p.name)
View Code
 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)
View Code
将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性


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)
View Code

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)
View Code
完全面向对象编程
先登录 后 实例化
还没有一个具体的对象的时候 就要执行login方法

使用什么样的方法要看具体用到了哪些名称空间中的变量
当一个方法要使用对象的属性时 就是用普通的方法
当一个方法要使用类中的静态属性时 就是用类方法
当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法

 





posted @ 2018-04-22 15:33  大白1#  阅读(42)  评论(0)    收藏  举报