【python基础】第35回 派生 封装 多态 反射
2022/7/29 1:22:49
本文主要是介绍【python基础】第35回 派生 封装 多态 反射,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录- 1. 派生
- 1.1 定义
- 1.2 派生方法的实战演练
- 1.2.1 推导 时间模块与json模块
- 1.2.2 解决方式1 转换数据类型
- 1.2.3 解决方式2 利用派生方法
- 2. 面向对象三大特征之封装
- 2.1 定义
- 2.2 特征
- 2.3 代码实例
- 3. property伪装属性
- 3.1 理解
- 3.2 扩展 体质指数(BMI)=体重(kg)÷身高^2(m)
- 3.3 代码实例
- 4. 面向对象三大特征之多态
- 4.1 定义
- 4.2 推导
- 4.2.1 推导1
- 4.2.2 推导2
- 4.2.3 结论
- 4.2.4 多态例子
- 4.3 强制操作,自觉遵守
- 4.4 鸭子类型
- 4.5 操作系统
- 5. 面向对象之反射
- 5.1 定义
- 5.2 主要方法
- 5.3 代码实例
- 5.3.1 方式1:利用异常处理(过于繁琐)
- 5.3.1 获取用户输入的名字,然后判断该名字对象有没有.
- 5.4 反射实战案列
1. 派生
1.1 定义
子类中定义类与父类一模一样的方法并且扩展了该功能:派生
即子类继承了父类,并且在子类中定义了与父类一样的方法
子类调用父类的方法super().父类的方法()
操作:拦截,添加,原路返回
1.2 派生方法的实战演练
1.2.1 推导 时间模块与json模块
import datetime import json a = { 't1': datetime.datetime.today(), 't2': datetime.date.today() } res = json.dumps(a) # 序列化 print(res)
由图可知代码会报错 无法正常序列化
raise TypeError(f'Object of type {o.__class__.__name__} ' TypeError: Object of type datetime is not JSON serializable
查看JSONEncoder源码发现序列化报错是有default方法触发的。
json序列化python 数据类型是有限制的 不是所有的类型都可以,要被序列化的数据,里里外外都必须是下述类型才可以
PYthon | JSON |
---|---|
dict | object |
list,tuple | array |
str | string |
int,float | number |
True | true |
False | false |
None | null |
1.2.2 解决方式1 转换数据类型
手动将不符合数据类型要求的数据转成符合要求的
a = { 't1': str(datetime.datetime.today()), 't2': str(datetime.date.today()) } res = json.dumps(a) print(res) # {"t1": "2022-07-28 15:16:41.417239", "t2": "2022-07-28"}
1.2.3 解决方式2 利用派生方法
如果想要避免报错 那么肯定需要对default方法做修改(派生)
a = { 't1': datetime.datetime.today(), 't2': datetime.date.today() } class MyJsonEncode(json.JSONEncoder): def default(self, o): '''o 就是json即将要序列化的数据''' if isinstance(o, datetime.datetime): return o.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(o, datetime.date): return o.strftime('%Y-%m-%d') # 如果是可以序列化的类型,那么不做任何处理,直接让他序列化即可 return super().default(o) res = json.dumps(a, cls=MyJsonEncode) print(res) # {"t1": "2022-07-28 16:05:23", "t2": "2022-07-28"}
2. 面向对象三大特征之封装
2.1 定义
封装其实就是将数据或者功能隐藏起来(包起来 装起来),隐藏的目的不是让用户无法使用,而是给这些隐藏的数据开设特定的接口,让用户使用接口才可以去使用,而我们在接口中添加一些额外的操作
2.2 特征
- 在定义阶段使用双下划线开头的名字,都是隐藏的属性,后续类和对象都是无法直接获取的
- 在python中不会真正的限制任何代码,隐藏的属性如果真的需要访问,也可以只不过需要做变形处理
- 格式 __变量名 = 值 _类名__变量名 = 值
- 隐藏就不改变使用变形之后的名字去访问,这样就是去了隐藏的意义
2.3 代码实例
class Student(object): __school = '清华大学' def __init__(self,name,age): self.__name = name self.__age = age # 专门开设一个访问学生数据的通道(接口) def check_info(self): print(""" 学生姓名:%s 学生年龄:%s """ % self.__name, self.__age) # 专门开设一个修改学生数据的通道(接口) def set_info(self, name, age): if len(name) == 0: print('用户名不能为空') return if not isinstance(age, int): print('年龄必须是数字') return self.__name = name self.__age = age stu1 = Student('jason', 18) stu1.set_info('','我很大')
3. property伪装属性
3.1 理解
可以简单的理解为,将方法伪装成数据
obj.name # 数据只需要点名字 obj.func() # 方法至少还要加括号
伪装之后可以将func方法伪装成数据 obj.func
3.2 扩展 体质指数(BMI)=体重(kg)÷身高^2(m)
class Person: def __init__(self, name, weight, height): self.name = name self.weight = weight self.height = height @property def BMI(self): return self.weight / (self.height ** 2) # BMI虽然需要计算获得 但是更像是人的数据 # TypeError: 'float' object is not callable # p1 = Person('jason', 70, 1.80) # res = p1.BMI() # print(res) p2 = Person('aaaa', 80, 1.70) print(p2.BMI) # 68166089965398
3.3 代码实例
class Foo: def __init__(self, val): self.__NAME = val # 将属性隐藏起来 @property def name(self): return self.__NAME @name.setter def name(self, value): if not isinstance(value, str): # 在设定值之前进行类型检查 raise TypeError('%s must be str' % value) self.__NAME = value # 通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter def name(self): raise PermissionError('Can not delete') obj = Foo('jason') # print(obj.name) # obj.name = 666 # print(obj.name) del obj.name
4. 面向对象三大特征之多态
4.1 定义
多态: 一种事物的多种形态
例:
水:液态,气态,固态
动物:人,狗,猫,猪
4.2 推导
4.2.1 推导1
class Animal(object): def spark(self): pass class Cat(Animal): def miao(self): print('喵喵喵') class Dog(Animal): def wang(self): print('汪汪汪') class Pig(Animal): def heng(self): print('哼哼哼') c1 = Cat() d1 = Dog() p1 = Pig() c1.miao() d1.wang() p1.heng()
4.2.2 推导2
class Animal(object): def spark(self): pass class Cat(Animal): def spark(self): print('喵喵喵') class Dog(Animal): def spark(self): print('汪汪汪') class Pig(Animal): def spark(self): print('哼哼哼') c1 = Cat() d1 = Dog() p1 = Pig() # c1.miao() # d1.wang() # p1.heng() c1.spark() d1.spark() p1.spark()
4.2.3 结论
一种事物有多种形态,但是相同的功能应该有相同的名字这样的话 以后我无论拿到哪个具体的动物 都不需要管到底是谁 直接调用相同的功能即可,无论你是鸡 鸭 猫 狗 猪 只要你想叫 你就调用固定的叫的功能
4.2.4 多态例子
不管在列表,字典,元组中统计个数都是用len
l1 = [11, 22, 33, 44] d1 = {'name': 'jason', 'pwd': 123, 'hobby': 'raed'} t1 = (11, 22, 33, 44) print(len(l1)) # 4 print(len(d1)) # 3 print(len(t1)) # 4
4.3 强制操作,自觉遵守
import abc # 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化 class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法 def talk(self): # 抽象方法中无需实现具体的功能 pass class Person(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准 def talk(self): pass def run(self): pass obj = Person()
4.4 鸭子类型
只要你长得像鸭子 走路像鸭子 说话像鸭子 那么你就是鸭子
# 都是人会跑会吃 class Teacher: def run(self):pass def eat(self):pass class Student: def run(self):pass def eat(self):pass
4.5 操作系统
- linux系统:一切皆文件
只要你能读数据 能写数据 那么你就是文件
# 内存 硬盘 class Txt: # Txt类有两个与文件类型同名的方法,即read和write def read(self): pass def write(self): pass class Disk: # Disk类也有两个与文件类型同名的方法:read和write def read(self): pass def write(self): pass class Memory: # Memory类也有两个与文件类型同名的方法:read和write def read(self): pass def write(self): pass
- python: 一切皆对象
只要你有数据 有功能 那么你就是对象
eg: 文件名 文件对象 模块名 模块对象
5. 面向对象之反射
5.1 定义
通过字符串来操作对象的数据或方法
5.2 主要方法
- hasattr():判断对象是否含有某个字符串对应的属性
- getattr():获取对象字符串对应的属性
- setattr():根据字符串给对象设置属性
- delattr():根据字符串给对象删除属性
5.3 代码实例
需求:判断用户提供的名字在不在对象可以使用的范围内
5.3.1 方式1:利用异常处理(过于繁琐)
变量名school 与字符串school 两者虽然只差了引号,但是本质是完全不一样的
stu.school stu.'school'
class Student: school = '清华大学' def choice_course(self): print('选课') stu = Student try: if stu.school: print(f"True{stu.school}") except Exception: print('没有属性')
5.3.1 获取用户输入的名字,然后判断该名字对象有没有.
以后只要在需求中看到了关键字(....对象....字符串)
那么肯定需要使用反射
while True: target_name = input('请输入您想要核查的名字>>>:').strip() '''上面的异常更加不好实现 需要用反射''' # print(hasattr(stu, target_name)) # print(getattr(stu, target_name)) if hasattr(stu, target_name): # print(getattr(stu, target_name)) res = getattr(stu, target_name) if callable(res): print('拿到的名字是一个函数', res()) else: print('拿到的名字是一个数据', res) else: print('不好意思,您想要查找的名字,对象没有') print(stu.__dict__) stu.name = 'jason' stu.age = 18 print(stu.__dict__) setattr(stu,'gender','male') setattr(stu,'hobby','read') print(stu.__dict__) del stu.name print(stu.__dict__) delattr(stu, 'age') print(stu.__dict__)
5.4 反射实战案列
class FtpServer: def serve_forever(self): while True: inp = input('input your cmd>>: ').strip() cmd, file = inp.split() if hasattr(self, cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性 func = getattr(self, cmd) # 根据字符串cmd,获取对象self对应的方法属性 func(file) def get(self, file): print('Downloading %s...' % file) def put(self, file): print('Uploading %s...' % file) obj = FtpServer() obj.serve_forever()
这篇关于【python基础】第35回 派生 封装 多态 反射的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-16`PyMuPDF4LLM`:提取PDF数据的神器
- 2024-11-16四种数据科学Web界面框架快速对比:Rio、Reflex、Streamlit和Plotly Dash
- 2024-11-14获取参数学习:Python编程入门教程
- 2024-11-14Python编程基础入门
- 2024-11-14Python编程入门指南
- 2024-11-13Python基础教程
- 2024-11-12Python编程基础指南
- 2024-11-12Python基础编程教程
- 2024-11-08Python编程基础与实践示例
- 2024-11-07Python编程基础指南