Python——面向对象
标签:obj,name,Python,res,self,多态,面向对象,print,def From: https://www.cnblogs.com/HaiMan/p/16866961.html派生方法实战
# coding:utf-8 import json import datetime # dict_demo = { # 't1': datetime.date.today(), # 't2': datetime.datetime.today(), # 't3': 'jason' # } # res = json .dumps(dict_demo) # 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、手动转换类型 # dict_demo = { # 't1': str(datetime.date.today()), # 't2': str(datetime.datetime.today()), # 't3': 'jason' # } # res = json.dumps(dict_demo) # print(res) ''' 可正常输出: {"t1": "2022-11-07", "t2": "2022-11-07 14:58:20.630274", "t3": "jason"} ''' # 2、派生方法 ''' 查看dumps源码,注意cls参数,默认传JsonEncoder if cls is None: cls = JSONEncoder 查看该类的源码,发现default方法时报错的发起者 def default(self, o): raise TypeError(f'Object of type {o.__class__.__name__} 'f'is not JSON serializable') 编写类继承JsonEncoder并重写default方法之后调用dumps手动传cls = 我们自己写的类 ''' dict_demo = { 't1': datetime.date.today(), 't2': datetime.datetime.today(), 't3': 'jason' } class MyJsonEncoder(json.JSONEncoder): def default(self, o): """ :param o:接收无法被序列化的数据 :return:返回可以被序列化的数据 """ if isinstance(o, datetime.datetime): return o.strftime('%Y-%m-%d %X') elif isinstance(o, datetime.date): return o.strftime('%Y-%m-%d') return super().default(o) res = json.dumps(dict_demo, cls=MyJsonEncoder) print(res) ''' {"t1": "2022-11-07", "t2": "2022-11-07 15:17:57", "t3": "jason"} '''
面向对象之封装
''' 封装: 将数据和功能'封装'起来 隐藏: 将数据和功能隐藏起来不让用户直接调用,而是通过一些接口,通过调用这些接口,间接的使用 ''' # coding:utf-8 # class C: # def func(self): # print('come on') # # # obj = C() # obj.func() # come on # # 将func方法伪装成类里面的数据 # obj.func # 目前运行没有任何效果 # class MyClass: # school_name = '清华大学' # _ = '文学系' # _name = 'HaiMan' # ''' # 在类的定义阶段,名字前面有两个下划线,那么该名字会被隐藏,无法被访问 # ''' # __age = '18' # ''' # 在Python中其实没有真正意义上的隐藏,仅仅是换了名字而已 # 用 类名._类名__名字可以访问 # ''' # def __choice_course(self): # print('正在选课') # # # print(MyClass.school_name) # 清华大学 # obj = MyClass() # print(obj.school_name) # 清华大学 # print(MyClass._) # 文学系 # # print(MyClass.__age) # 报找不到对应的对象的属性错 # ''' # AttributeError: type object 'MyClass' has no attribute '__age'. Did you mean: '_name'? # ''' # MyClass.__hobby = 'read' # # 在类定义阶段之外,不会被隐藏 # print(obj.__hobby) # read # print(MyClass._MyClass__age) # 18 # print(MyClass.__dict__) # 查看类里面所有的名字 class Person: def __init__(self, name, age, hobby): # 对象也可以拥有隐藏的属性 self.__name = name self.__age = age self.__hobby = hobby def get_info(self): # 在类体代码中,是可以直接使用,隐藏的名字的 print(f""" name: {self.__name} age: {self.__age} hobby: {self.__hobby} """) # 隐藏的属性开放修改的接口,可以自定义很多功能 def set_name(self, new_name): if len(new_name) == 0: raise ValueError('Please input name') if new_name.isdigit(): raise ValueError('Please dont\'t input digit' ) self.__name = new_name obj = Person('HanMan', 18, 'read') print(obj.get_info()) ''' name: HanMan age: 18 hobby: read ''' print(obj.set_name('jason')) print(obj.get_info()) ''' name: jason age: 18 hobby: read ''' ''' 在今后编写面向对象代码类的定义时,还有很多单下划线开头的名字 表达的意思通常是不要直接访问,而是看看下面可能定义的接口 '''
伪装
''' 伪装: 将类里面的方法伪装成类里面的数据 BMI指数:衡量一个人的体重与身高对健康影响的一个指标 体质指数(BMI)=体重(kg)÷身高^2(m) EX:70kg÷(1.75×1.75)=22.86 ''' # coding:utf-8 # class Person: # 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('HaiMan', 1.80, 80) # p1.BMI() # BMI应该作为人的基本数据而不是方法 # 报错TypeError: # print(p1.BMI) # 24.691358024691358 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(f'{value} must be str') # 通过类型检查后,将值value存放到真实的位置 self.__NAME = value @name.deleter def name(self): raise PermissionError('Can not delete') f = Foo('HaiMan') print(f.name) # HaiMan f.name = 'HaiMan888' print(f.name) # HaiMan888 del f.name ''' f.name = 'HaiMan' # 触发name.setter装饰器对应的函数name(f,’HaiMan') f.name = HaiMan123 # 触发name.setter对应的的函数name(f,HaiMan),抛出异常TypeError del f.name # 触发name.deleter对应的函数name(f),抛出异常PermissionError '''
多态
# coding:utf-8 """ 面向对象中多态意思是 一种事物可以有多种形态但是针对相同的功能应该定义相同的方法 这样无论我们拿到的是哪个具体的事物 都可以通过相同的方法调用功能 """ """ python永远提倡自由简介大方 不约束程序员行为 但是多态提供了约束的方法 """ import abc # 指定metaclass属性将类设置为抽象类, # 抽象类本身只是用来约束子类的,不能被实例化 class Animal(metaclass=abc.ABCMeta): # 该装饰器限制子类必须定义有一个名为talk的方法 @abc.abstractmethod def talk(self): print('talk') class Cat(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准 def talk(self): print('miao') # 若子类中没有一个名为talk的方法则会抛出异常TypeError, # 无法实例化 cat = Cat() print(cat.talk()) # miao
反射
''' 利用字符串操作对象的数据和方法 1.hasattr() 重点 判断对象是否含有某个字符串对应的属性名或方法名 2.getattr() 重点 根据字符串获取对象对应的属性名(值)或方法名(函数体代码) 3.setattr() 根据字符串给对象设置或者修改数据 4.delattr() 根据字符串删除对象里面的名字 ''' # coding:utf-8 ''' 利用字符串操作对象的数据和方法 1.hasattr() 重点 判断对象是否含有某个字符串对应的属性名或方法名 2.getattr() 重点 根据字符串获取对象对应的属性名(值)或方法名(函数体代码) 3.setattr() 根据字符串给对象设置或者修改数据 4.delattr() 根据字符串删除对象里面的名字 ''' # class C1: # school = '剑桥大学' # # def choice_course(self): # print('please choice course') # # # obj = C1() # obj.choice_course() # please choice course ''' 判断某个名字对象是否存在 推导思路 try: obj.xxx except AttributeError: print('your dont have the name') 判断用户随意指定的名字是否存在 target_name = input('Please input your need judge name') try: obj.target_name except AttributeError: print('your dont have the name') ''' class C1: school_name = '清华大学' def choice_course(self): print('please choice your course') obj = C1() while True: target_name = input('Please input your need judge name>>>:') if hasattr(obj, target_name): print('congratulate you! name is exists') # 获取改名字对应的数据(func data) data_or_func = getattr(obj, target_name) if callable(data_or_func): print('it is a func') data_or_func() else: print('it is a data', data_or_func) else: print('the name is not exists')
反射实战案例
''' 1.什么时候应该考虑使用反射 只要需求中出现了关键字 对象....字符串.... 2.实战案例 1.模拟cmd终端 ''' # coding:utf-8 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: target_cmd = input('请输入您的指令>>>:') res = target_cmd.split(' ') if len(res) == 1: if hasattr(self, res[0]): getattr(self, res[0])() else: print(f'{res[0]}不是内部或者外部命令') elif len(res) == 2: if hasattr(self, res[0]): getattr(self, res[0])(res[1]) else: print(f'{res[0]}不是内部或者外部命令') obj = WinCmd() obj.server_run() ''' 2.一切皆对象 ''' # 利用反射保留某个py文件中所有的大写变量名及对应的数据值 import settings print(dir(settings)) # dir列举对象可以使用的名字 useful_dict = {} for name in dir(settings): if name.isupper(): useful_dict[name] = getattr(settings, name) print(useful_dict) # while True: # target_name = input('请输入某个名字') # if hasattr(settings, target_name): # print(getattr(settings, target_name)) # else: # print('该模块文件中没有该名字')