首页 > 其他分享 >面向对象之封装和多态

面向对象之封装和多态

时间:2022-11-07 19:48:46浏览次数:36  
标签:封装 name self 多态 面向对象 名字 print class def

  • 派生方法实战演练
  • 面向对象三大特性之封装
  • 面向对象三大特性之多态
  • 面向对象之反射
  • 反射的实战案例

派生方法实战演练

import json
import datetime

d = {'t1': datetime.date.today(),
     't2': datetime.datetime.today(),
     't3': 'jason'}
res = json.dumps(d)
print(res)
"""
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type date is not JSON serializable
序列化报错:不是可序列化类型
"""
"""
能够被序列化的数据是有限的>>>:里里外外都必须是下列左边的类型
    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+
"""
转换方式1:手动转(将不可序列化的手动转字符串等可序列化类型)
d = {'t1': str(datetime.date.today()),
     't2': str(datetime.datetime.today()),
#      }
res = json.dumps(d)
print(res)  # {"t1": "2022-11-07", "t2": "2022-11-07 14:54:59.789983"}
转换方式2:派生方法
"""
查看dumps源码,注意cls参数,默认转JsonEncoder
查看该类的源码,发现default方法是报错的发起者
编写类继承JsonEncoder并重写default方法,之后调用dumps手动传cls=我们自己的类
"""

d = {'t1': str(datetime.date.today()),
     't2': str(datetime.datetime.today()),
     }
class My_JsonEncoder(json.JSONEncoder):
    def default(self, o):
        """
        :param o: 接收无法被序列化的数据
        :return: 返回可以被序列化的数据
        """
        if isinstance(o, datetime.datetime):  # 如果o的数据类型是datetime.datetime
            return o.strftime('%Y-%m-%d %X')
        elif isinstance(o, datetime.date): # 如果o的数据类型是datetime.date
            return o.strftime('%Y-%m-%d')
        return super().default(o)  # 如果都不是的话还是调用原来的方法
res = json.dumps(d,cls=My_JsonEncoder)
print(res)  # {"t1": "2022-11-07", "t2": "2022-11-07 15:05:24.140046"}

面向对象三大特性之封装

封装:就是将数据和功能封装起来
隐藏:将数据和功能隐藏起来不让用户直接调用,而是开发一些接口间接调用,从而可以在接口内添加额外的操作
伪装:将类里面的方法伪装成类里面的数据
'伪装':
    class C:
        def func(self):pass
    boj = C()  # 产生对象
    boj.func()  # 对象调用类中的方法
    '经过伪装'
    boj.func  # 实现伪装,其实还是boj.func()

隐藏

class MyClass:
    school_name = '老男孩大学'
    _ = '嘿嘿嘿'
    _name = 'tony'
    """类在定义阶段,名字前面有两个下划线,该名字就会被隐藏起来,无法直接访问"""
    __age = 18
    """在python中没有真正的隐藏,仅仅是换了个名字_类名__名字"""

    def choice_course(self):
        print('学生正在选课')


print(MyClass.school_name)  # 老男孩大学
obj = MyClass()  # 产生一个对象
print(obj.school_name)  # 老男孩大学
print(MyClass._)  # 嘿嘿嘿
print(MyClass._name)  # tony
print(MyClass.__age)  # 报错,显示没有这个名字
MyClass.__hobby = 'JDB'  # 无法隐藏,这句话表示在类中添加数据
print(MyClass.__hobby)  # JDB
obj.__age  # 报错,显示没有这个名字
obj.__addr = '派出所'  # 这句话表示在对象中添加数据

隐藏的实际用法

class Person:
    def __init__(self, name, age, hobby):
        self.__name = name  # 对象也可以拥有隐藏的属性
        self.__age = age
        self.__hobby = hobby

    def get_info(self):
        # 在类体代码中,是可以直接使用隐藏名字,然后打印
        print(f"""
        姓名:{self.__name}
        年龄:{self.__age}
        爱好:{self.__hobby}
        """)

    # 隐藏的属性开放修改的接口,可以自定义很多功能,也可以增加一些限制
    def set_name(self, new_name):  # 修改名字的接口
        if len(new_name) == 0:
            raise ValueError('名字不能没有')
        if new_name.isdigit():
            raise ValueError('名字不能是数字')
        self.__name = new_name  # 在类的定义阶段,是可以点出来隐藏的名字


obj = Person('jason', 18, 'read')
obj.get_info()  # 姓名:jason 年龄:18 爱好:read
obj.set_name('tony老师')  # 调用修改名字的接口
obj.get_info()  # 就是名字就是修改后的tony老师
"""
以后我们在编写面向对象代码类的定义时,也会看到很多单下划线开头的名字
表达的意思通常特指不要直接访问,而是查找一下下面可能定义的接口
"""

伪装

BMI指数:衡量一个人的体重与身高对健康影响的一个指标
    体质指数(BMI)=体重(kg)÷身高^2(m)
	 EX:70kg÷(1.75×1.75)=22.86
class Person(object):
    def __init__(self, name, height, weight):
        self.name = name
        self.height = height
        self.weight = weight

    @property
    def BMI(self):
        return self.weight / (self.height ** 2)


p1 = Person('jason', 1.83, 78)
p1.BMI()  # BMI应该作为人的基本数据而不是方法
print(p1.BMI)  # 利用装饰器伪装成数据
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存放到真实的位置

    @name.deleter  # 删除名字,直接报错,不能删除
    def name(self):
        raise PermissionError('Can not delete')


f = Foo('jason')
print(f.name)  # jason,这是由于伪装的原因
f.name = 'jason123'
print(f.name)
del f.name  # 删除直接报错, Can not delete
f.name = 'jason'  # 触发name.setter装饰器对应的函数name(f,’jason')
f.name = 123  # 触发name.setter对应的的函数name(f,123),抛出异常TypeError
del f.name  # 触发name.deleter对应的函数name(f),抛出异常PermissionError

三大特性之多态

多态:一种事务的多种形态
	水:液态,固态,气态
   动物:人,猪,猫,狗
class Animal:
    def spark(self):
        """叫的方法"""
        pass


class Cat(Animal):  # 子类继承父类Animal
    def miao(self):
        print('喵喵喵')


class Dog(Animal):
    def wang(self):
        print('汪汪汪')


class Pig(Animal):
    def heng(self):
        print('哼哼哼')
"""以上都属于动物的叫声,属于叫声的多态性,实际的写法应该为下面"""
class Animal:
    def spark(self):
        """叫的方法"""
        pass


class Cat(Animal):  # 子类继承父类Animal
    def spark(self):
        print('喵喵喵')


class Dog(Animal):
    def spark(self):
        print('汪汪汪')


class Pig(Animal):
    def spark(self):
        print('哼哼哼')
"""
面向对象中多态意思是 一种事务可以有多种形态但是针对相同的功能应该定义相同的方法,这样不论我们拿到的是哪个具体的事务,都可以通过相同的方法调用功能
"""
s1 = 'hello word'
L1 = [11,22,33,44]
d = {'name':'jason','pwd':123}
print(s1.__len__())
print(l1.__len__())
print(d.__len__())
'不同的数据类型,调用长度的方法都是len其实也是一种多态的表现'
"""
鸭子类型:只要你看上去像鸭子,走路像鸭子,说话像鸭子,那么你就是鸭子
"""
# linux系统
"""
文件      能够读取数据也能够保存数据
内存      能够读取数据也能够保存数据
硬盘      能够读取数据也能够保存数据
......
一切皆文件
"""
多态的正确写法:
class File:
    def read(self): pass

    def write(self): pass


class Memory:
    def read(self): pass

    def write(self): pass


class Disk:
    def read(self): pass

    def write(self): pass
"""python永远提倡自由简介大方,不约束程序员行为,但是多态提供约束的方法"""
import abc


# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod  # 该装饰器限制子类必须定义有一个名为talk的方法
    def talk(self):  # 抽象方法中无需实现具体的功能
        pass


class Cat(Animal):  # 但凡继承Animal的子类都必须遵循Animal规定的标准
    def talk(self):
        pass


cat = Cat()  # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化

面向对象之反射

利用字符串操作对象的数据和方法
1.hasattr()  重点
	判断对象是否含有某个字符串对应的属性名或方法名
2.getattr()  重点
	根据字符串获取对象对应的属性名(值)或方法名(函数体代码)
3.setattr()
	根据字符串给对象设置或修改数据
4.delattr()
	根据字符串删除对象里面的名字
class C1:
    school_name = '小姐姐学院'

    def choice_course(self):
        print('大宝贝们正在选课')

反射推导:
obj = C1()  # 生成一个对象
"""判断某个名字对象是否可以使用(存在)"""
推导思路
try:
    obj.xxx
except AttributeError:
    print('你木有这个名字')
"""判断用户随意指定的名字对象是否可以使用(存在)"""
traget_name = input('请输入对象可能使用的名字>>>:').strip()
try:
    obj.traget_name
except AttributeError:
    print('你木有这个名字')
"""输入存在的名字也显示没有是因为用户输入的是字符串,而我们的点的是变量名"""
'反射:利用字符串操作对象的数据和方法'
print(hasattr(obj, 'school_name'))  # 返回True,证明有
print(getattr(obj, 'school_name'))  # 获取这个字符串对应属性名的值
print(getattr(obj, 'choice_course'))  # 获取的是函数体代码


class C1:
    school_name = '小姐姐学院'

    def choice_course(self):
        print('大宝贝们正在选课')


obj = C1()  # 生成一个对象
while True:
    target_name = input('请输入您想要操作的名字>>>:').strip()
    if hasattr(obj, target_name):  # 判断用户输入的名字是否有
        print('恭喜您 系统中有该名字')
        # 获取该名字对应的数据值
        date_or_func = getattr(obj,target_name)  # 有的话getattr获取这个名字的值
        if callable(date_or_func):  # callable判断这个名字是否可以加括号
            print('您本次使用的是系统中的某个方法')
            date_or_func()  # 判断是可以加括号的,我们直接调用
        else:
            print('您本次使用的是系统中某个数据')  # 如果不是就可以直接打印
            print(date_or_func)  # 打印这个值
    else:
        print('很抱歉,系统中没有该名字')

反射实战案例

1.什么时候应该考虑使用反射,只要需求中出现了关键字
	对象...字符串...
2.实战案例
1.模拟cmd终端
class WinCmd:
    def tasklist(self):  # 方法名
        print("""
        1.学习编程
        2.学习python
        3.守护妹妹
        """)

    def ipconfig(self):  # 方法名
        print("""
        地址:127.0.0.1
        地址:上海浦东新区
        """)

    def get(self, target_file):  # 方法名
        print('获取指定文件', target_file)

    def put(self, target_file):  # 方法名
        print('上传指定文件', target_file)

    def server_run(self):  # 方法名
        print('欢迎进入简易版本cmd终端')
        while True:
            traget_cmd = input('请输入您的指令>>>:').strip()
            res = traget_cmd.split(' ')  # 切割空格  # 按照空格切割成一个列表,来区分用户输入的是单个名字还是有俩
            if len(res) == 1:  # 如果这个列表的长度是1,证明列表里面只有一个元素
                if hasattr(self, res[0]):  # 判断列表里面的字符串有没有这个名字
                    getattr(self, res[0])()  # 如果有的话加括号获取这个值,然后加括号调用
                else:
                    print(f'{res[0]}不是内部或者外部命令')  # 如果没有这个名字就打印
            elif len(res) == 2:  # 如果列表的长度是2.证明调用的是上传或者获取文件,第一个元素是方法名,第二个元素是文件名
                if hasattr(self, res[0]):  # 判断列表里面有没有索引0的名字
                    getattr(self, res[0])(res[1])# 有的话,直接getattr,索引0获取这个名字的值调用,将列表索引1作为参数传进去                else:
                else:
                    print(f'{res[0]}不是内部或者外部命令')
obj = WinCmd()  # 生成一个对象
obj.server_run()  # 调用类中的方法
2.一切皆对象
import seetings

print(dir(seetings))  # 获取文件里面所有的名字
useful_dict = {}  # 先定义一个字典
for name in dir(seetings):  # 循环获取名字
    if name.isupper():  # 如果名字是大写
        useful_dict[name] = getattr(seetings, name)  # 获取对象seetings里面name对应的值,增加键值对
print(useful_dict)
while True:
    target_name = input('请输入某个名字>>>:').strip()
    if hasattr(seetings, target_name):  # 如果在对象settings里面有这个名字
        print(getattr(seetings, target_name))  # 就直接打印这个名字
    else:
        print('该模块文件中没有该名字')

标签:封装,name,self,多态,面向对象,名字,print,class,def
From: https://www.cnblogs.com/zhanghong1229/p/16867174.html

相关文章

  • 派生方法实例、面向对象三大特性之封装、多态和反射
    目录一.派生方法实战演练二.面向对象三大特性之封装封装伪装三.三大特性之多态四.面向对象之反射利用字符串操作对象的数据和方法反射实战案例一.派生方法实战演练import......
  • 面向对象:派生,三大特性封装,多态,反射
    派生实操importjsonimportdatetimed={'t1':datetime.date.today(),'t2':datetime.datetime.today(),'t3':'jason'}res=json.dumps(d)prin......
  • 面向对象之多态/反射
    派生方法的更多应用importjsonimportdatetimea={'t1':datetime.date.today(),'t2':datetime.datetime.today(),'t3':'moon'}res=json.dumps(a)......
  • 面向对象三大特性之封装、多态
    目录一、派生方法实战演练举例:时间对象序列化报错1转换方式一:手动转类型2转换方式二:派生方法二、面向对象三大特性之封装0.封装简介1.隐藏2.伪装属性(1)装饰器@property:......
  • 面向对象之反射
    目录一、面向对象之反射1.hasattr(object,name)2.getattr()3.setattr(object,name,value)4.delattr(object,name)二、反射实战案例1.使用反射的场景:2.案例(1)模拟终端(2......
  • 面向对象三大特性封装,多态,反射
    派生方法实战演练importjsonimportdatetimed={'ti':datetime.date.today()'t2':datetime.datetime.today()'t3':'jason'}res=json.dumps(d)pr......
  • 面向对象之封装、多态、反射
    面向对象之封装、多态、反射面向对象之封装封装:将数据和功能‘封装’起来隐藏:将数据和功能隐藏起来不让用户直接调用,并开发一些接口间接调用,而且可以在接口内添加一些......
  • Python基础之面向对象:5、三大特征-多态
    面对对象之多态目录面对对象之多态一、多态1、多态的概念2、多态的实际应用1、自我约束2、abc模块一、多态1、多态的概念​ 多态在实际应用时较为抽象,指事物的多种形态......
  • Python基础之面向对象:6、三大特征-封装
    面向对象之封装目录面向对象之封装一、封装1、封装的概念2、为什么要封装3、封装的两个层面二、隐藏与调用的方法1、隐藏的方法2、调用与修改的方法三、伪装1、伪装的概念......
  • Python基础之面向对象:7、反射
    面向对象之反射目录面向对象之反射一、反射1、反射的定义2、使用的场景3、常用方法1.hasattr()2.getattr()3.setattr()4.delattr()4、反射的实际应用一、反射1、反射的......