7月28日 python派生方法,封装,多态以及反射
- 
派生方法的实战演练(重要)
- 
面向对象三大特性之封装
- 
面向对象三大特性之多态
- 
面向对象之反射(重要)
- 
property伪装属性
1.派生方法演练
直接看代码,这里我们获取时间并序列化
import datetime import json d = { 't1': datetime.datetime.today(), 't2': datetime.date.today() } res = json.dumps(d) # 序列化字典 print(res)
但是结果报错 无法正常序列化 raise TypeError(f'Object of type {o.__class__.__name__} '
Object of type datetime is not JSON serializable
json序列化python数据类型是有限制的 不是所有的 想要运行上述代码 就需要把日期类型转为字典类型数据
查看可序列化类型源码的方式
json.JSONEncoder
+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str | string |
+-------------------+---------------+
| int, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+
方法1 手动把不符合数据类型要求的数据转成符合要求的
d = { 't1': str(datetime.datetime.today()), # 用str将日期转为字典类型数据 't2': str(datetime.date.today()) } res = json.dumps(d) print(res)
方法2 利用派生方法
""" 查看JSONEncoder源码发现序列化报错是有default方法触发的 raise TypeError(f'Object of type {o.__class__.__name__} ' f'is not JSON serializable') 我们如果想要避免报错 那么肯定需要对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') # super 派生关键字 如果是可以序列化的类型 那么不做任何处理 直接让它序列化即可 return super().default(o) res = json.dumps(d, cls=MyJsonEncode) print(res)
2 面向对象三大特性之封装
封装其实就是将数据或者功能隐藏起来(包起来 装起来)
隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的接口 让用户使用接口才可以去使用 我们在接口中添加一些额外的操作
2-1 在类定义阶段使用双下划线开头的名字 都是隐藏的属性后续类和对象都无法直接获取
class Person: __school = '清华' def eat(self): print('python太好玩啦') obj = Person() print(Person.__school) # 报错 无法获取
2-2 在python中不会真正的限制任何代码隐藏的属性 只是把变量名改了名字
__变量名 >>> _类名__变量名
如果真的需要访问也可以, 只不过需要做变形处理 这里我们把数据做了封装 并自定义了接口以及数据展现格式 想要获取数据就必须使用这个接口才可以(这就是封装的意义)

3
class Animal(object): class Cat(Animal): def spark(self): print('喵喵喵') class Dog(Animal): def spark(self): print('汪汪汪') class Pig(Animal): def spark(self): print('哼哼哼') """ 例如动物Animal有多个形态 Cat, Dog, Pig,而Cat, Dog, Pig有同样的功能’叫‘,那么我们给他们直接定义相同的功能’spark‘ 当需要他们叫的直接调用固定的功能就可以 """ c1 = Cat() d1 = Dog() p1 = Pig() c1.spark() d1.spark() p1.spark()
特殊的多态:
当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子
就如上面的例子中,当我们使用spark()方法时,并不会对对象的类型进行判断,而是直接执行对象所属的类中的对应方法,这就是鸭子类型,鸭子类型只需要保证传入的对象有一个talk()方法就可以了
4 面向对象之反射
反射就是通过字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动
可使用反射的地方:
4-1、反射类中的变量 : 静态属性,类方法,静态方法
4-2、反射对象中的变量、对象属性、普通方法
4-3、反射模块中的变量
4-4、反射本文件中的变量
反射的四个方法:
4-1:hasattr(): 判断对象是否含有某个字符串对应的属性
判断对象是否有某个属性,有就返回True,没有就返回False
class A:
name = 'zs'
age = 18
if hasattr(A,'name'):
print(hasattr(A, 'name'))
结果:
 
4-2:getattr(): 获取对象字符串对应的属性
"""用法:getattr(obj,str,default=None) 判断obj中是否有str属性,有就返回,没有时有传入第三参数就返回第三参数,没有就报错。""" class A: name = 'zs' age = 18 print(getattr(A,'name')) print(getattr(A,'language','notfound'))
结果:
 
4-3:setattr(): 根据字符串给对象设置属性
class A: name = 'zs' age = 18 setattr(A,'name','ls') setattr(A,'language','Chinese') print(getattr(A,'name')) print(getattr(A,'language','notfound'))
结果:
 
4-4:delattr(): 根据字符串给对象删除属性
"""删除后判断是否有该属性有就返回True,没有就返回False"""
class A: name = 'zs' age = 18 delattr(A,'name') # 删除 print(hasattr(A,'name')) # 判断
结果:
5.property伪装函数
可以简单的理解为 将方法伪装成数据
         obj.name   # 数据只需要点名字
         obj.func()  # 方法至少还要加括号
伪装之后可以将func方法伪装成数据 obj.func
property有三部分内容:
@property是装饰器,可以用来将类中的方法伪装成属性;
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) p1 = Person('jason', 78, 1.83) print(p1.BMI) # 直接调用数据即可
另外
@方法名.setter也是装饰器,在修改伪装成属性的方法值时会调用它;
@方法名.deleter还是装饰器,在删除伪装成属性的方法值时会调用它。


 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号