python之面向对象3
派生方法的实际应用
何为派生上一篇已经介绍过了,总结一下就是:拦截 添加 原路返回
有一个关键词super()
子类继承了父类 并且在子类中定义了与父类一样的方法
eg:子类调用父类的方法 super().父类的方法()
------------
用派生给json序列化不支持对象序列化
import datetime
import json
d = {
't1':datetime.datetime.today(),
't2':datetime.date.today()
}
# res = json.dumps(d)
# print(res) # 报错 无法用json序列化
查看JSONEncoder源码发现序列化报错是有default方法触发的
我们如果想要避免报错 那么肯定需要对default方法做修改(派生)
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(d, cls=MyJsonEncode)
print(res) # {"t1": "2022-07-28 15:08:32", "t2": "2022-07-28"}
json.dumps(d, cls=MyJsonEncode)
# 只要cls的参数是自己写的那么datetime也是可以序列化的 同样可以扩展其他序列化不支持的类型 一劳永逸的办法
***在子类中实现这个方法,就可以返回一个‘o’可以序列化的对象
json可序列化对象和数据类型
Supports the following objects and types by default:
# 默认支持以下对象和类型
+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str | string |
+-------------------+---------------+
| int, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+
To extend this to recognize other objects, subclass and implement a
``.default()`` method with another method that returns a serializable
object for ``o`` if possible, otherwise it should call the superclass
implementation (to raise ``TypeError``).
# 要拓展它来识别其他对象,子类化并实现.default()方法和另一个返回可序列化对象的方法,将‘o’作为对象,否则应调用父类。
面向对象三大特性之封装
# 封装就是将数据或功能隐藏起来
class Person:
__name = 'summer'
__school = '清华大学'
__hobby = 'study'
# 在类定义阶段使用双下划线开头的变量名默认是隐藏属性 不可以直接调用
def info(self):
# 给隐藏的变量设置一个方法 对象可以直接调用方法来获取数据
return f'''
姓名: {self.__name}
学校: {self.__school}
爱好: {self.__hobby}
'''
# 类体隐藏属性的变量在类体内是可以直接使用的 类体外不可以直接调用
def study(self):
print('是人都要会敲代码!!!!!!')
res = Person()
print(res.study()) # 是人都要会敲代码!!!!!!
print(res.info())
# 姓名: summer
# 学校: 清华大学
# 爱好: study
隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的接口 让用户使用接口才可以去使用 我们在接口中添加一些额外的操作
# python的隐藏属性也不是完全隐藏 还是可以通过变形之后的名字取调用的
print(res._Person__name) # summer
此方法不推荐使用 会失去隐藏的意义
property伪装属性
# 简单理解就是将方法伪装成数据,调用的话直接用点名字的方式就可以
体质指数(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)
res = Person('summer',50,1.7)
p = res.BMI() # 没加装饰器之前的调用
print(p) # 17.301038062283737
# 加了装饰器之后的调用
print(res.BMI) # 17.301038062283737
面向对象三大特性之多态
多态:简单来讲就是事物的多种形态
class Animal: # 同一类事物:动物
def talk(self):
pass
class Cat(Animal): # 动物的形态之一:猫
def talk(self):
print('喵喵喵')
class Dog(Animal): # 动物的形态之二:狗
def talk(self):
print('汪汪汪')
class Pig(Animal): # 动物的形态之三:猪
def talk(self):
print('哼哼哼')
# 实例化得到三个对象
cat = Cat()
dog = Dog()
pig = Pig()
cat.talk() # 喵喵喵
dog.talk() # 汪汪汪
pig.talk() # 哼哼哼
多态性指的是可以在不用考虑对象具体类型的情况下而直接使用对象,这时候我们就需要把他设置成统一的使用方法便于调用
鸭子类型
“鸭子类型”(duck typing):“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”
class Teacher:
def run(self):pass
def eat(self):pass
class Student:
def run(self):pass
def eat(self):pass
# 不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象
------------
python:一切皆对象
只要你有数据 有功能 那么你就是对象
文件名 文件对象
模块名 模块对象
面向对象之反射
反射就是通过字符串来操作对象的数据和方法
class Student:
school = '北京大学'
def choice_coures(self):
print('选课')
s1 = Student()
# 判断用户提供的名字在不在对象使用范围内
# 方式1 利用异常捕获 方法太麻烦
try:
if s1.school:
print(f'True,{s1.school}') # True,北京大学
except Exception:
print('没有该属性')
# 方式2
while True:
target_name = input('请输入想要查询的名字》》》:').strip()
# print(hasattr(s1,target_name)) # True
# print(getattr(s1, target_name))
# 北京大学 不存在的名字会报错
# 可以让程序不报错,两个方法结合使用
if hasattr(s1, target_name):
# print(getattr(s1,target_name)) # 下图1示例
res = getattr(s1, target_name)
# 让程序更优化
if callable(res): #下图2示例
# callable()方法 判断括号内变量是否能加括号调用 可以返回Ture 不可以返回False
print('名字是个函数', res())
else:
print('拿到的名字是一个数据', res)
else:
print('该名字不存在')
方法3:
# setattr
print(s1.__dict__) # {}
setattr(s1,'name','summer')
setattr(s1,'age','18')
print(s1.__dict__) # {'name': 'summer', 'age': '18'}
方法4:
#delattr
name = input('请输入想要删除的名字》》》:').strip() # summer
delattr(s1,'name')
print(s1.__dict__) # {'age': '18'}
反射的四个方法总结
反射主要就四个方法
hasattr():判断对象是否含有某个字符串对应的属性
# 上述案例的方式一和方式二
getattr():获取对象字符串对应的属性
# 上述案例的方式一和方式二
setattr():根据字符串给对象设置属性
# 上述案例的方法3
delattr():根据字符串给对象删除属性
# 上述案例的方法4
eg1:
eg2:
反射案例(很重要!!!)
反射在实际中需要用的时候:
以后只要在需求中看到了关键字
....对象....字符串
那么肯定需要使用反射
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()
# input your cmd>>: get a.txt
# Downloading a.txt...
# input your cmd>>: put a.txt
# Uploading a.txt...
例如生活中的一些只能小家电音箱之类的 ,只要你对着它说出你的指令它就会根据获得的关键字开启相应的功能。只不过我们在程序中是用户输入的方式获得关键字
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!