1.多态
2.封装:
1.封装属性
2.封装方法
3.封装的原理
4.封装存在的问题
5.计算属性
3.类中内置函数
1.多态
多态是一种概念,指的是某种事物具备多个不同形态
例如 水:气态,固态,液态
动物:猫,狗,猪
OOP 中,标准解释:多个不同类型对象 可以响应同一个方法 并且产生不同结果
多态的好处:
只需要学习基类中的使用方法即可,不需要关心具体的哪一类,以及实现的,以不变应万变,提高了扩展性
案例:
2.封装
什么是封装:
对外部隐藏内部的属性,以及实现细节,给外部提供使用的接口
注意:
封装有隐藏的意思,但不是单纯的隐藏
学习封装的目的:
就是为了能够限制外界对内部数据的访问
python中属性的权限分为两种:
1.公开的:没有任何限制,谁都可以访问
2.私有的:只有当前类本身能够访问
默认为公共的
如何封装:
在类内定义的属性前加 __ 开头的方法
为什么要封装:
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 show_id_card(self): # 可以在这里添加额外的任何逻辑代码,来限制外部的访问 # 在类的内部,可以访问 print(self.__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位')
封装方法:
一个为内部提供支持的方法,不应该让外界直接访问,那就直接封装起来
class ATM: def withdraw(self): # 输出账号和密码 self.__user_auth() self.__input_money() self.__save_record() def __user_auth(self): print('请输入账号密码。。。') def __input_money(self): print('余额为1000000000,请输入取款金额') def __save_record(self): print('记录流水。。。。。。') atm = ATM() # 以下功能无法单独调用 # atm.user_auth() # atm.input_money() # atm.save_record() # 必须通过此接口来调用 atm.withdraw()
Property
Property作用:
将一个方法伪装成普通属性
为什么用property :
希望将访问私有属性和普通属性的方式变得一致
与property相关的两个装饰器
setter
用点语法给属性赋值时出发
deleter
用点语法删除属性时出发
案例:
# 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): del self.__dict__['_Teacher__salary'] ''' 通常,property 用于操作私有属性 被封装的属性在访问时,需要调用方法,而普通属性直接点就OK,这样一来对于对象的使用者而言 就必须知道要访问的属性,是私有的还是公开的,然后调用对应的方法,使用起来比较麻烦,而property装饰器的方法 就是将访问私有属性和普通属性的方式变得一致 ''' t = Teacher('egon',38,100000) print(t.salary) # 100000 直接调用 t.salary = 500 print(t.salary) # 500 直接修改 # 删除对象 del t.name print(t.__dict__) # {'age': 38, '_Teacher__salary': 500} 没有name属性了
计算属性:
什么是计算属性,一个属性它的值不是固定死的,而是通过动态产生的
''' property 的另一种使用场景,计算属性 什么是计算属性 一个属性,它的值不是固定死的,而是通过计算动态产生的 比如下面案例BMI ''' class Person: def __init__(self, name, height, weight): self.name = name self.height = height self.weight = weight # BMI公式 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.8,70) # print(p.BMI) p.weight = 65 print(p.BMI) # 被封装的内容(私有的) 不可以被继承
3.类中内置函数
__str__
''' 类中的__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__函数 str(p)
__del__
''' __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() # 在程序结束时,会执行del,把文件清理关闭。 def __del__(self): print('del run') self.file.close() p = Person('rose', '本周内容') print(p.read_data())
反射:
# 英文中叫反省(自省) # 面向对象中的反省指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力 # 一个对象在设计初期,可能考虑不够周全后期需要删除或修改已存在的属性,和增加属性 # 反射就是通过字符串来操作对象属性 # 涉及到的方法: # hasattr() 判断是否存在某个属性 # getattr() 获取某个属性 # setattr() 新增或修改某个属性 # delattr() 删除某个属性 import os 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...!')
动态导入模块:
直接写import 称之为静态导入,建立在一个基础上:提前已经知道有这个模块
动态导入 指的是:在需要的任何时候,通过指定字符串类型的包名称来导入需要的模块
''' 直接写import 称之为静态导入 ,建立在一个基础时,提前已经知道有这个模块 动态导入:指的时 在需要的任何时候 通过指定字符串类型包名称来导入需要的模块 import importlib mk 即导入成功的模块 ''' import importlib m_name = input('请输入要导入的模块名称:') mk = importlib.import_module(m_name) print(mk) from build_house import conf print(conf)