Day33 继承的三大特性之 封装与多态

Day33 面向对象的三大特性之 封装与多态

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__} '
# TypeError: Object of type datetime is not JSON serializable




'''
通过 查看dumps 中默认参数 得知有个cls 默认为None 然后 成为 JSONEncoder类的对象,该对象中 如果 要序列话的数据类型不属于下列九种数据类型就会主动报错
    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+

if cls is None:
    cls = JSONEncoder

def default(self, o):
    raise TypeError(f'Object of type {o.__class__.__name__} '
                    f'is not JSON serializable')

'''
#通过查看源码 发现报错的代码出自 default 所以我们尝试 修改 defoult方法 让他按我们做的defoult来

class MyClass(json.JSONEncoder):
    # 参数 o 就是 要 被序列化的数据
    def default(self, o):
        if isinstance(o,datetime.datetime):
            # 截获 该不符合条件的 datetime。datetime类型数据,通过 strftime转为 字符串类型输出
            return o.strftime('%y-%m-%-d %X')
        elif isinstance(o,datetime.date):
            # 截获 该不符合条件的 datetime。datetime类型数据,转为 字符串类型输出
            return o.strftime('%y-%m-%d')
        # 将正常 符合条件 还是按原本的default输出
        return super().default(o)

res = json.dumps(d,cls=MyClass),
print(res)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
('{"t1": "22-07-28 15:33:56", "t2": "22-07-28"}',)

2、面向对象三大特性之封装

封装其实就是将数据或者功能隐藏起来(包起来,装起来)

隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的接口 让用户使用接口才可以去使用 我们在接口中添加一些额外的操作

在类定义阶段使用双下滑线开头的名字 都是隐藏的属性
后续类喝对象都无法直接获取

在python 中不会真正的限制任何代码
隐藏属性 如果真的需要访问 也可以 只不过需要做变形处理
__变量名>>> _类名__变量名
既然隐藏了 就不该 使用变形之后的名字 去访问 不然就失去了其原本的隐藏意义了

class Student(object):
    __school = '北京大学'

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    # 查看封装后的数据的通道,也叫接口
    def check_info(self):
        print("""
        学生姓名:%s
        学生年龄:%s
        学校:%s
        """ % (self.__name, self.__age, self.__school))

    # 创建一个 修改数据的通道 (接口)
    # 参数中要有 要修改的数据的参数
    def set_info(self, name, age, school):
        if len(name) == 0:
            print('用户不饿能为空')
            return
        if not isinstance(age, int):
            print('年龄 必须是数字')
            return
        self.__name = name
        self.__age = age
        self.__school= school


s1 = Student('kk', '18')
#查看 接口内数据
s1.check_info()
#通过接口 修改 类中封装数据
s1.set_info('kk',20,'哈佛')
s1.check_info()

3、property 伪装属性

可以简单的理解为 将方法伪装成 数据

数据与方法的使用方式

obj.name 数据只需要点名字

obj.func() 方法至少还要加括号
伪装之后可以将func方法伪装成数据 obj.func

代码举例

#伪装属性
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('kk',57,1.7)
#print(p1.BMI())
#当我们 给 方法上面加一个 property装饰器 语法糖 那么 该方法 在被调用就不需要 使用括号
#print(p1.BMI)  # 此时 该BMI 数据 虽然是通过 方法内计算来的 但是更像是一个 数据
>>>>>>>>>>>>>>>>>>>>>>>>>>
19.723183391003463

匿名方法拓展

#匿名 拓展
class Person:
    def __init__(self, name, weight, height):
        self.__name = name
        self.weight = weight
        self.height = height
    # 该装饰语法 将 普通的查看 封装好的name的接口 函数 伪装为 数据方式
    @property
    #查看 封装函数 数据 的接口
    def name(self):
        return self.__name
    #将 修改 封装好的 数据 变为像数据 一样 可以直接 =要修改的值  相当于 等号后面跟实参
    @name.setter
    #修改 封装好的 数据 
    def name(self,value):
        self.__name=value

p1=Person('kk',57,1.7)
# print(p1.BMI())

print(p1.name)

p1.name='hh'
print(p1.name)
  • 上诉两装饰器语法结合 使用 可以将 封装的数据 使用起来变得跟普通数据一样

4、面向对象三大特性之多态

多态: 一种事物的多种形态
水:液态 气态 固态
动物:人 狗 猫 猪

一种事物有多种形态 但是相同的功能 应该有 相同的名字
这样的话 以后我们无论 拿到哪个具体的动物 都不需要 管到底是谁 直接调用相同的功能即可
无论 你是 鸡 鸭 猫 狗 猪 只要你想叫 你就调固定的 叫的功能

代码举例

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.spark()
d1.spark()
p1.spark()

多态的概念 其实我们很早之前就已经接触过

例如 列表 元组 字典 在查找 元素个数的时候我们用len 方法,但他们 都是 不同的数据类型和结构
这显然 就是 将 方法名统一为len

鸭子类形
只要你长得像鸭子,走路像鸭子,说话像鸭子,那么你就是鸭子

你不需要 继承共同的 父类 当你们的方法 类似时 也要将方法名统一名称

操作系统

Linux (一切 皆文件)

只要你额能读数据 能写数据 那么你就时文件

那么不管 硬盘 、内存、文件 的读和取 的方法名都要相同

一切皆对象
在python世界里 所有的东西都可以看成是对象
例如 文件名 文件对象
模块名 模块对象
变量名 变量对象

5、面向对象之反射

反射: 通过字符串来操作对象的数据或方法

主要的四个反射方法:
hasattr :判断对象是否含有某个字符串对应的属性
getattr :获取对象字符串对应的属性
setattr :根据字符串给对象设置属性
delattr :根据字符串给对象删除属性

class Student:
    school = '清华大学'

    def choice_course(self):
        print('选课')

s1 = Student()

while True:
    # 获取用户输入的 方法或数据名
    target_name = input('请输入您想要核查的名字>>>:').strip()
    # 判罚是否存在于该对象中
    if hasattr(s1, target_name):
		#判断 是否能被括号调用
        res = getattr(s1, target_name)
        #能就是 方法 直接 通过getattr 直接调用打印返回值
        if callable(res):
            print('是函数', res())
        #没有则 为 数据
        else:
            print('是数据', res)
    else:
        print('不好意思 您想要查找的名字 对象没有')

5.1、反射实战案例

  • 反射 的功能 很强大 很好用 主要你到 后面 学了django会有体现
class FtpServer:
    def serve_forever(self):
        while True:
            # 用户 输入 包含 方法的 文本 (可以设定格式)例如get a.txt
            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()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值