封装语法
数据角度:将一些基本的数据类型复合成了自定义类
优点
1、建立与数据与数据之间的连接
2、代码可读性强(通过类可以查看到对象的属性或方法)
缺点
从行为角度理解:数据(属性、方法)会暴露,可以任意操作
行为角度:类外提供必要的功能,隐藏实现的细节
优点
使用者不用去了解内部的实现细节,只需要关注对外提供的功能。
私有成员
demo1:私有后,不能直接访问
# 私有成员
class Student:
def __init__(self, name, age, score):
self.name = name
self.__age = age # 私有变量
self.score = score
# 私有成员可以在类内直接访问(推荐)
def __show_infos(self):
print('姓名:%s,年龄:%d,成绩:%d' % (
self.name, self.__age, self.score))
# 在类外访问
stu = Student('YY', 18, 66)
# print(stu.__age) # AttributeError
# 查看实例对象的变量字典
print(stu.__dict__)
# python的类中没有绝对的私有化,只是做了【屏蔽】
print(stu._Student__age) # 不推荐(私有化,强行访问)
# 通过实例方法访问
# stu.show_infos() # 私有方法在类外不能直接访问
stu._Student__show_infos() # 不推荐【‘防君子不防小人’】
# 问题:以上方式在类外不能直接访问.如果要访问?
demo2:不符合面向对象
# 问题:以上方式在类外不能直接访问.如果要访问?
# 措施:
# 1、私有化实例变量
# 2、提供2个公开的方法(读、写方法)
class Student:
def __init__(self, name, age, money):
self.name = name
self.age = age
self.__money = money # 私有变量
def get_money(self): # 读取方法
return self.__money
def set_money(self, value): # 写入方法
self.__money = value
stu = Student('老毕', 18, 10000)
# print(stu._Student__money)
# stu._Student__money += 100
# print(stu._Student__money)
# 读取
print(stu.get_money())
# 修改
stu.set_money(11000)
print(stu.get_money())
# 问题:实例化对象无法查看到当前自身的属性,不符合面向对象的语法。
demo3:属性引入
# 私有成员
# 问题:实例化对象无法查看到当前自身的属性,不符合面向对象的语法。
# 措施:
# 1、私有化实例变量
# 2、提供2个公开的方法(读、写方法)
class Student:
def __init__(self, name, age, money):
self.name = name
self.age = age
self.money = money
self.set_money(money)
def get_money(self): # 读取方法
return self.__money
def set_money(self, value): # 写入方法
self.__money = value
stu = Student('老毕', 18, 10000)
print(stu.__dict__)
# 读取
print(stu.get_money())
# 修改
stu.set_money(11000)
print(stu.get_money())
# 问题:为了实例对象多添加一个属性,不是解决咱们的问题。
demo4:属性添加 property作用
property作用:拦截将对变量的操作拦截给了对方法的操作!why?变量无法给予逻辑,方法可以。。
# 私有成员
# 问题:为了实例对象多添加一个属性,不是解决咱们的问题。
数据修改不符合规范,超出正常范围
# 措施:
#1、创建实例变量
#2、提供2个公开的方法(读、写方法)
#3、创建类变量存储property对象
# 目的:
# 实现了对实例变量的保护,符合Python面向对象的语法
# 在为实例对象添加money属性时,调用set_money方法,为实例对象添加私有属性money
class Student:
def __init__(self, name, age, money):
self.name = name
self.age = age
self.money = money #程序执行的是property那行代码
# self.set_money(money)
def get_money(self): # 读取方法
return self.__money
def set_money(self, value): # 写入方法
if 0 <= value <= 20000: # 数据有效性验证
self .__money = value
else:
raise Exception('数据超过正常范围') # 抛出异常
# 添加实例变量money时建立set_money的联系(类变量)
# 将实例变量修改为了私有变量
money = property(get_money, set_money)
# print('类变量:', money)
stu = Student('老毕', 18, 10000)
print(stu.__dict__)
# 读取
print(stu.get_money())
# 访问类变量
print(Student.money)
print(stu.money)
# 修改
stu.set_money(1100000)
print(stu.get_money())
# 问题:现在读写方法访问太多麻烦,采用:实例对象.实例成员
demo5:标准属性:保护数据
针对于demo4而言,不用类变量
# 问题:现在读写方法访问太多麻烦,采用:实例对象.实例成员
# 措施:
#1、创建实例变量
#2、提供2个公开的方法(读、写方法)
#3、使用@property修饰读取方法 使用@属性名.setter修改写入方法
# 目的:
# 实现了对实例变量的保护,符合Python面向对象的语法, 实现数据有效性验证
class Student:
def __init__(self, name, age, money):
self.name = name
self.age = age
self.money = money
@property #创建property对象 自动绑定下面方法(读取方法)
# 方法名必须和属性名称相同 不能叫get_money了 此处money可以理解为存储property对象的变量
def money(self): # 读取方法
return self.__money
@money.setter #给property对象绑定下面方法(写入方法) 同样的方法名要叫money
def money(self, value): # 写入方法
if 0 <= value <= 20000: # 数据有效性验证
self.__money = value
else:
raise Exception('数据超过正常范围') # 抛出异常
# money = property(get_money, set_money)
stu = Student('老毕', 18, 10000)
print(stu.__dict__)
# 读取(调用了读取方法)
print(stu.money)
# 修改(调用了写入方法)
stu.money = 12000
print(stu.money)
属性@property总结
常见写法
可读可写
class 类名([父类]):
def __init__(self, 参数):
self.属性名 = 参数
...
@property
def 属性名(self): # 读取方法(返回私有变量)
return self.__属性名
@属性名.setter
def 属性名(self, value): # 写入(修改:第1次实例化为实例对象添加对应属性时)
# 数据有效性验证
self.__属性名 = value
只读
class 类名([父类]):
def __init__(self, 参数):
self.__属性名 = 参数
...
@property
def 属性名(self): # 读取方法(返回私有变量)
return self.__属性名
只写
class 类名([父类]):
def __init__(self, 参数):
self.属性名 = 参数
...
def 属性名(self, value): # 写入(修改:第1次实例化为实例对象添加对应属性时)
# 数据有效性验证
self.__属性名 = value
属性名 = property(None, 属性名)
封装设计思想
分而治之 变则疏之
高内聚 低耦合
分而治之
将一个大需求分解为许多类,每个类处理一个独立的功能
变则梳之
变化的地方独立封装,避免影响其他类
高内聚
类中哥哥方法都在完成一项任务
类的职责要单一
低耦合
类与类的关联性与依赖度要低
每个类独立,让一个类的改变,尽少影响其他类