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中不会真正的限制任何代码隐藏的属性 只是把变量名改了名字

__变量名  >>>   _类名__变量名

如果真的需要访问也可以, 只不过需要做变形处理   这里我们把数据做了封装    并自定义了接口以及数据展现格式 想要获取数据就必须使用这个接口才可以(这就是封装的意义)

 

向对象三大特性之多态

一个对象具有多种形态, 在不同的使用环境中以不同的形态展示其功能, 那么我们就称该对象具有多态特征。所以我们可以给多态一个简单的定义:一个类继承了其他类的功能, 根据不同的场景, 切换不同的形态, 做到不同的功能, 我们就称之为多态。

 

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还是装饰器,在删除伪装成属性的方法值时会调用它。

posted @ 2022-07-28 19:37  你好你好你好丶  阅读(79)  评论(0)    收藏  举报