自学Python5.7-面向对象三大基本特征_封装
自学Python之路-Python基础+模块+面向对象
自学Python之路-Python网络编程
自学Python之路-Python并发编程+数据库+前端
自学Python之路-django
自学Python5.7-面向对象三大基本特征_封装
一、封装
1.1 封装概念
广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种封装,只让自己的对象调用自己的方法。
狭义上的封装:面向对象的三大基本特征之一,隐藏对象的属性和实现细节,仅对外提供公共访问方式。
封装的好处:
- 将变化隔离;
- 便于使用;
- 提高复用性;
- 提高安全性;
封装原则:
- 将不需要对外提供的内容都隐藏起来;
- 把属性都隐藏,提供公共方法对其访问。
class Person: def __init__(self,name,passwd): self.name = name self.passwd = passwd carlos = Person("carlos","carlos7628") print(carlos.passwd) # 打印出carlos的密码
1.2 私有属性
1.2.1 私有属性,在外部调用不到
# 若不想别人查看carlos的密码 class Person: def __init__(self,name,passwd): self.name = name self.__passwd = passwd #加上"__",隐藏属性,----私有属性 carlos = Person("carlos","carlos7628") print(carlos.__passwd)
1.2.2 私有属性,使用一种方法可以在外部调用(通常不使用)
class Person: def __init__(self,name,passwd): self.name = name self.__passwd = passwd #加上"__",隐藏方法 carlos = Person("carlos","carlos7628") print(carlos.__dict__) # 查看属性里面都有什么
此时查看到密码的真实属性是“_Person__passwd'”, 再来print一下:
class Person: def __init__(self,name,passwd): self.name = name self.__passwd = passwd #加上"__",隐藏方法 carlos = Person("carlos","carlos7628") print(carlos._Person__passwd) # _类的名字__属性的名字,就能查看到私有属性的内容
1.2.3 私有属性,只要在类的内部使用私有属性,就会自动的转换成带上_类名
class Person: def __init__(self,name,passwd): self.name = name self.__passwd = passwd #加上"__",隐藏方法 , def get_pwd(self): return self.__passwd #只要在类的内部使用私有属性,就会自动的转换成带上_类名。 就是_Person__passwd carlos = Person("carlos","carlos7628") print(carlos._Person__passwd) print(carlos.get_pwd())
1.2.4 只要在类的内部使用私有属性,就会自动的转换成带上_类名,就是_Person__passwd。但是在类的外部不是的。
class Person: def __init__(self,name,passwd): self.name = name self.__passwd = passwd #加上"__",隐藏方法 def get_pwd(self): print(self.__dict__) return self.__passwd #只要在类的内部使用私有属性,就会自动的转换成带上_类名 carlos = Person("carlos","carlos7628") print(carlos._Person__passwd) carlos.__high = 181 print(carlos.get_pwd()) print(carlos.__high)
举例:
# 定一个房子类, 计算面积 class Room: def __init__(self,name,length,width): self.name = name self.__length = length #私有属性 self.__width = width #私有属性 def area(self): return self.__length * self.__width Tong = Room('Tong',2,1) print(Tong.area())
现在有个问题,如果更改name,使用方法如下:
class Room: def __init__(self,name,length,width): self.name = name self.__length = length self.__width = width def area(self): return self.__length * self.__width Tong = Room('Tong',2,1) print(Tong.area()) Tong.name = "Carlos" print(Tong.name)
最好的解决办法如下,name采用私有属性。 (对私有属性的保护,不可以随便更改名字name)
class Room: def __init__(self,name,length,width): self.__name = name self.__length = length self.__width = width def get_name(self): return self.__name def set_name(self,newName): if type(newName) is str and newName.isdigit() == False: # 非数字的字符串 self.__name = newName else: print('不合法的姓名') def area(self): return self.__length * self.__width Tong = Room('Tong',12,6) print(Tong.area()) # 打印tong房子的面积 Tong.set_name("carlos") # 设置名字为carlos print(Tong.get_name()) Tong.set_name("2") # 设置了非法的名字2 print(Tong.get_name())
1.2.5 父类的私有属性不能被子类调用
# 父类的私有属性不能被子类调用 class Foo: __key = '123' # _Foo__key 静态私有属性 class Son(Foo): print(Foo.__key) # _Son__key
1.3 私有方法
class Person: def __init__(self,name,passwd): self.name = name self.__passwd = passwd #加上"__",隐藏方法 def __get_pwd(self): #私有方法 return self.__passwd #只要在类的内部使用私有属性,就会自动的转换成带上_类名 def login(self): # 正常的方法调用私有的方法 self.__get_pwd()
1.4 总结
- # 所有的私有 都是在变量的左边加上双下划綫
- 对象的私有属性
- 类中的私有方法
- 类中的静态私有属性
- # 所有的私有的 都不能在类的外部使用
- # 采用私有概念的场景:①隐藏起一个属性 ,不想让类的外部调用;②我想保护这个属性,不想让属性随意被改变;③我想保护这个属性,不被子类继承
二、property内置函数
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值。
举例1: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 People: 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) p1=People('carlos',75,1.85) print(p1.bmi) # @Property直接调用属性bmi====== 没有Property调用方法bmi()
举例2: 圆的面积和周长
from math import pi class Circle: def __init__(self,r): self.r = r def permeter(self): return 2*pi*self.r def area(self): return self.r**2*pi c1 = Circle(5) print(c1.permeter()) #圆的周长 print(c1.area()) #圆的面积
from math import pi class Circle: def __init__(self,r): self.r = r @property def permeter(self): return 2*pi*self.r @property def area(self): return self.r**2*pi c1 = Circle(5) print(c1.permeter) #圆的周长,可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值 print(c1.area) #圆的面积
注意:此时的特性area和perimeter不能被赋值。
1 from math import pi 2 class Circle: 3 def __init__(self,r): 4 self.r = r 5 @property 6 def permeter(self): 7 return 2*pi*self.r 8 @property 9 def area(self): 10 return self.r**2*pi 11 c1 = Circle(5) 12 c.area=3 #为特性area赋值
为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。
面向对象的封装有三种方式:
- 【public】这种其实就是不封装,是对外公开的
- 【protected】这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
- 【private】这种封装对谁都不公开
python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现。
class Foo: def __init__(self,val): self.__NAME=val #将所有的数据属性都隐藏起来 @property def name(self): return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置) @name.setter def name(self,value): if not isinstance(value,str): #在设定值之前进行类型检查 raise TypeError('%s must be str' %value) self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter def name(self): raise TypeError('Can not delete') f=Foo('egon') print(f.name)
f.name=10 #抛出异常'TypeError: 10 must be str' del f.name #抛出异常'TypeError: Can not delete'
一个静态属性property本质就是实现了get,set,delete三种方法。
class Foo: @property def AAA(self): print('get的时候运行我啊') @AAA.setter def AAA(self,value): print('set的时候运行我啊') @AAA.deleter def AAA(self): print('delete的时候运行我啊') #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
class Foo: def get_AAA(self): print('get的时候运行我啊') def set_AAA(self,value): print('set的时候运行我啊') def delete_AAA(self): print('delete的时候运行我啊') AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
实际超市促销的例子:
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 print(obj.price) del obj.price # 删除商品原价
三、classmethod内置函数
class Classmethod_Demo(): role = 'dog' @classmethod def func(cls): print(cls.role) Classmethod_Demo.func()
四、staticmethod内置函数
class Staticmethod_Demo(): role = 'dog' @staticmethod def func(): print("当普通方法用") Staticmethod_Demo.func()
.....
作者:CARLOS_CHIANG
出处:http://www.cnblogs.com/yaoyaojcy/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
posted on 2019-08-13 13:23 CARLOS_KONG 阅读(330) 评论(0) 编辑 收藏 举报