注意:封装有隐藏的意思,但不是单纯的隐藏
学习封装的目的.就是为了能够限制外界对内部数据的访问
python中属性的权限分为两种
1.公开的
没有任何限制 谁都能访问
2.私有的
只有当前类本身能够访问
默认为公共的
1.提高安全性
封装属性
2.隔离复杂度
封装方法
在一个类中分为属性和方法两种数据
1. 封装属性
class Student: def __init__(self,name,age,gender,id_card): self.name = name self.age = age self.gender = gender self.__id_card = id_card #添加--来将类中的属性隐藏,不对外界直接开放,在程序中提供查看和调用的接口 def show_id_card(self): # 可以在这里添加额外的任何逻辑代码 来限制外部的访问 # 提供给外界调用查看属性的接口 #在类的内部 可以访问 print(self.__id_card)
可以对私有属性的访问进行修改
对封装的属性进行修改操作的函数中 get 表示访问器, 使用set 表示设置器
class Student: def __init__(self,name,age,gender,id_card): self.name = name self.age = age self.gender = gender self.__id_card = id_card # 访问被封装的属性 称之为访问器 def get_id_card(self,pwd): # 可以在这里添加额外的任何逻辑代码 来限制外部的访问 例如加入访问密码判断的限制 # 在类的内部 可以访问 if pwd =="123": return self.__id_card raise Exception("密码错误!") # 修改被封装的属性 称之为设置器 def set_id_crad(self,new_id): # 身份证必须是字符串类型 # 长度必须是18位 if isinstance(new_id,str) and len(new_id) == 18: self.__id_card = new_id else: raise Exception("身份证号码 必须是字符串 且长度必须为18!")
什么样的方法应该被封装起来
一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来 ,如下例中的 银行银行系统中的用户各类信息,如
用户密码,用户余额等个人信息。.
class ATM: def withdraw(self): self.__user_auth() self.__input_money() self.__save_record() # 输入账号和密码 # 显示余额 # 输入取款金额 # 保存记录 以下函数接口为提供给外界调用查看的路径,封装的作用并不是将信息锁死,可以作为起保护作用来看待封装的作用 def __user_auth(self): print("请输入账号密码....") def __input_money(self): print("余额为100000000,请输入取款金额!") def __save_record(self): print("记录流水....")
封装的原理和接口的原理类似通过变形的方式来实现封装
实现方式上在名称前面带有双下划线的变量名前面加上-类名。
变形后可以直接访问被隐藏的属性,但是一般不这样操作,可以但没有必要。
变形只会在类的定义阶段发生一次,之后在添加的双划线开头的属性就只是普通属性了。
class Person: def __init__(self,name,age,id_card): self.name = name self.age = age self.__id_card = id_card def get_id_card(self): return self.__id_card p = Person("rose",20,"321123123123123123") print(p.name) p.__id_card = "321" print(p.__dict__) #打印结果:{'name': 'rose', 'age': 20, '_Person__id_card': '321123123123123123', '__id_card': '321'}
可以看出只是属于新添加的一个对象属性。
print(p._Person__id_card) p.__gender = "man" print(p.__dict__)
#和上一个打印结果相同,后加入只是被当作普通属性来进行添加{'name': 'rose', 'age': 20, '_Person__id_card': '321123123123123123', '__id_card': '321', '__gender': 'man'}
当属性被隐藏之后访问方式就和访问普通属性有些不同,需要用定义的对象点出接口后在加个括号有些麻烦。
这里使用装饰器来实现访问和访问普通属性一致 property
class Teacher: def __init__(self,name,age,salary): self.name = name self.age = age self.__salary = salary @property # getter # 用于访问私有属性的值 也可以访问普通属性 def salary(self): return self.__salary @salary.setter # 用来设置私有属性的值 也可以设置普通属性 def salary(self,new_salary): self.__salary = new_salary @salary.deleter # 用来设置私有属性的值 也可以删除普通属性 def salary(self): # print("can not delete salary!") del self.__dict__["_Teacher__salary"]
class Person: def __init__(self,name,height,weight): self.name = name self.height = height self.weight = weight # self.BMI = weight / (height ** 2) @property def BMI(self): return self.weight / (self.height ** 2) 接口处添加计算方式,这样当用户输入自己的真实身高体重时就会通过这个
接口,得出自己的真实的体重状况 @BMI.setter def BMI(self,new_BMI): print("BMI 不支持自定义.....") p = Person("egon",1.7,80) print(p.BMI) p.BMI = 10
多态 :
多态不是一个具体的技术 或代码
class Cat(): def bark(self): print("喵喵喵") def run(self): print("四条腿跑!") def sleep(self): print("趴着睡!") class Pig(): def bark(self): print("哼哼哼!") def run(self): print("四条腿跑!") def sleep(self): print("侧躺着睡!") # 一个用来管理动物的方法 只要你传入是一个动物 我就按照动物的标准来使用 完全不用考虑你具体是什么类型 def management_animal(animal): print("==================正在溜%s=============" % animal.__class__.__name__) animal.bark() animal.run() animal.sleep()
__del__
当对象被删除前会自动调用 该方法
声明时候会删除对象?
1.程序运行结束 解释器退出 将自动删除所有数据
2.手动调用del 时也会删除对象
注意:该函数不是用来删除对象的
使用场景
当你的对象在创建时,开启了不属于解释器的资源 例如打开了一个文件
必须保证当对象被删除时 同时关闭额外的资源 如文件
也称之为析构函数 构造 的反义词
构造 指的是从无到有
析构 值从有到无
简单的说就对象所有数据全部删除
总结:__del__该函数 用于 在对象删除前做一些清理操作
# 假设要求每一个person对象都要绑定一个文件 class Person: def __init__(self,name,path,mode="rt",encoding="utf-8"): self.name = name self.file = open(path,mode,encoding=encoding) # 读取数据的方法 def read_data(self): return self.file.read() def __del__(self): print("del run!") self.file.close()
英文中叫反省 (自省)
面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力;
一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性
hasattr 判断是否存在某个属性
getattr 获取某个属性的值
setattr 新增或修改某个属性
delattr 删除某个属性
案例:
```python class MY_CMD: def dir(self): os.system("dir") def ipconfig(self): os.system("ipconfig") cmd = MY_CMD() while True: name = input("请输入要执行的功能:") if hasattr(cmd,name): #首先判断判断属性是否存在 method = getattr(cmd,name) #存在则通过getter来获取该属性 print(method) method() else: print("sorry this method is not exists....!") ```
import importlib
mk = importlib.import_module(m_name)
mk 即导入成功的模块
"""
该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类