多态:
就是指多个不同类型对象,可以响应同一个方法,得到不同结果。
好处是:只需要学习基类中的使用方法即可,不需要关心具体的哪一个类,以及实现的,以不变应万变,提高了灵活性,提高了扩展性。
class Person():
def bark(self):
print("Hello!")
def run(self):
print("两条腿跑!")
def sleep(self):
print("躺着睡!")
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("侧躺着睡!")
person1 = Person()
cat1 = Cat()
pig1 = Pig()
person1.sleep()
cat1.sleep()
pig1.sleep()
如果没有多态 需要分别学习 person cat pig 的不同使用方法 这对于使用者而言太麻烦了
# 一个用来管理动物的方法 只要你传入是一个动物 我就按照动物的标准来使用 完全不用考虑你具体是什么类型
def management_animal(animal):
print("==================正在溜%s=============" % animal.__class__.__name__)
animal.bark()
animal.run()
animal.sleep()
# 来了一堆动物
person1 = Person()
cat1 = Cat()
pig1 = Pig()
management_animal(person1)
management_animal(cat1)
management_animal(pig1)
封装:
什么是封装:
对外部隐藏内部的属性,以及实现细节,给外部提供使用的接口
注意:封装有隐藏的意思,但不是单纯的隐藏
学习封装的目的,就是为了能够限制外界对内部数据的访问。
python中属性的权限分为两种
1.公开的
没有任何限制,谁都能访问
2.私有的
只有当前类本身能够访问
默认为公共的
好处是:提高安全性(封装属性),隔离复杂度(封装方法)
一个类中分为两种数据,属性和方法
封装属性:
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!")
什么样的方法应该被封装起来:
一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来,如下例中的user_auth等
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("记录流水....")
封装的原理:
python是通过变形的方式来实现的封装
如何变形 在名称带有双下划线开头的变量名子前添加_类名,ru_Person_id_card
当然通过变形后的名字可以直接访问被隐藏的属性,但通过不应该这么做,变形仅在类的定义阶段发生一次,后续再添加的带有双下划线的任何属性都不会变形,就是普通属性。
封装方法:
一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来。
Property
作用:将应该方法伪装成普通属性
为什么用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 不支持自定义.....")
常用的内置函数
__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:删除某个属性
案例:
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 importlib
mk = importlib.import_module(m_name)
mk即导入成功的模块
该方式常用在框架中,因为框架设计者不可能提前预知后续需要的模块和类。