1.封装
封装定义: 对外部隐藏内部的属性、方法,给外部提供使用的接口 __属性 或__方法 再python中,封装有隐藏的意思,但不是单纯的隐藏 封装的目的:限制外界对内部数据的访问 python中属性的权限分为两种,默认为公开的 1.公开的:没有任何限制 谁都能访问 2.私有的:只有当前类本身能够访问 封装原理: python是通过变形的方式来实现的封装 变形:在名称带有双下划线开头的变量名字前添加_类名 如_Person__id_card 当然通过变形后的名字可以直接访问被隐藏的属性 但不应该这么做 变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形 就是普通属性 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!")
为何封装: 1.提高安全性 封装属性 对外限制直接访问,因此对属性进行封装 2.隔离复杂度 封装方法 为何要封装方法: 一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来 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("记录流水....")
2.property装饰器
# 被封装的属性在访问时 需要调用方法 而普通属性直接点就ok 这样一来对于对象的使用者而言 # 必须知道要访问的属性 是私有的还是公开 然后调用对于的方法 用起来麻烦 # 此时 我们的目标是 让访问私有属性 和访问普通属性的方式一致 # property 装饰器 :将一个方法伪装成属性 与property相关的 两个装饰器 setter 用点语法 给属性赋值时触发 deleter 用点语法删除属性时触发 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"]
property的另一种使用场景 计算属性 什么是计算属性 一个属性 它的值不是固定死的 而是通过计算动态产生的 如:BMI身体质量指数 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
3.多态
多态:指的是 多个不同类型对象 可以响应同一个方法 ,产生不同结果 多态并不是一个具体的技术或代码 多态 某种事物具备多个不同形态 例如 水: 气态 固态 液态 动物: 人 猫 猪 汽车人: 汽车 飞机 人型 OOP中 标准解释: 多个不同类型对象 可以响应同一个方法 并且产生不同结果 多态的带来的好处: 只需要学习基类中的使用方法即可, 不需要关心具体的哪一个类 以及实现的 以不变应万变 提高了灵活性 提高扩展性 如果没有多态 需要分别学习 person cat pig 的不同使用方法 这对于使用者而言太麻烦了 如何实现多态: 鸭子类型 就是典型的多态 多种不同类型 使用方法一样 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()
4.类中的内置函数
类中的__str__ 该方法在object中有定义 默认行为 返回对象类型以及地址 如:<__main__.Person object at 0x0000016F450C7390> 在将对象转为字符串时执行 注意:返回值必须为字符串类型 子类可以覆盖该方法来完成 对打印内容的自定义 class Person: def __init__(self,name,age): self.name = name self.age = age # 将对象转换为字符串时执行 def __str__(self): print("str run") return "my name is %s , age is %s" % (self.name,self.age) p = Person("rose",20) print(p)#在打印前都会现将要打印的内容转为字符串 通过调用__str__函数
__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() p2 = Person("rose","本周内容") print(p2.read_data())
5.反射
英文中叫反省 (自省) 面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力; 一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性 反射就是通过字符串来操作对象属性 实现方法: hasattr 判断是否存在某个属性 getattr 获取某个属性的值 setattr 新增或修改某个属性 delattr 删除某个属性 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) print(method) method() else: print("sorry this method is not exists....!")
6.动态导入
直接写import 称之为静态导入 建立在一个基础上:提前已经知道有这个模块 动态导入 指的是 在需要的任何时候 通过指定字符串类型的包名称来导入需要的模块 import importlib m_name = input("请输入要导入的模块名称:") mk = importlib.import_module(m_name) #mk 即导入成功的模块 print(mk) 该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类