python知识-派生演练、面向对象三大特性、反射知识

派生方法的实战演练

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
json序列化python数据类型是有限制的 不是所有的类型都可以
(Ctrl+json.JSONEncoder鼠标左键查看)
+-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+
ps:即将要被序列化的数据 里里外外都必须是上述类型才可以
"""
# 解决方式1:手动将不符合数据类型要求的数据转换成符合要求的
# d = {
#     't1': str(datetime.today()),
#     't2': str(datetime.date.today())
# }
# res = json.dumps(d)
# print(res)
# 解决方式2: 利用派生方法
d = {
    't1': datetime.datetime.today(),
    't2': datetime.date.today()
}
#  res = json.dumps(d)
"""class JSONEncoder:
    pass
dumps(obj,cls=None):
    if cls ==None:
        cls = JSONEncoder
    return cls(...)  #  JSONEncoder()
    查看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')
       # 如果是可以序列化的类型 那么不做任何处理 直接让他序列化即可
        return super().default(o)

res = json.dumps(d,cls=MyJsonEncode)
print(res)
json.dumps(d,cls=MyJsonEncode)

面向对象三大特性之封装

封装其实就是将数据或者功能隐藏起来(包起来 装起来)
隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的接口 让用户使用接口可以去使用 我们在接口中添加一些额外的操作

1.在类定义阶段使用双下划綫开头的名字 都是隐藏的属性
	后续类和对象都无法直接获取
2.在python中不会真正的限制任何代码
	隐藏的属性如果真的需要访问也可以 只不过需要做变形处理
    _变量名 _类名 _变量名
   ps:既然隐藏了就不改使用变形之后的名字去访问 这样就失去了隐藏的意义
class Student(object):
    __school = '清华大学'

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

    # 专门开设一个访问学生数据的通道(接口)
    def check_info(self):
        print("""
        学生姓名:%s
        学生年龄:%s
        """ % (self.__name, self.__age))

    # 专门开设一个修改学生数据的通道(接口)
    def set_info(self, name, age):
        if len(name) == 0:
            print('用户名不能为空')
            return
        if not isinstance(age, int):
            print('年龄必须是数字')
            return
        self.__name = name
        self.__age = age


stu1 = Student('jason', 18)
stu1.set_info('', '我很大')
"""
我们编写python很多时候都是大家墨守成规的东西 不需要真正的限制
精简写法
class A:
	_school = '清华大学'
	def _choice_course(self):
		pass
"""

property伪装属性

可以简单的理解为 将方法伪装成数据
	obj.name   # 数据只需要点名字
	obj.func()  # 方法至少还要加括号
伪装之后可以将func方法伪装成数据 obj.func

扩展了解
	体质指数(BMI)=体重(kg)÷身高^2(m)
# 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)
# res = p1.BMI()
# print(res)
# p2 = Person('悍匪', 72, 1.73)
# res = p2.BMI()
# print(res)
"""BMI虽然需要计算获得 但是更像是人的数据"""
# p1 = Person('jason', 78, 1.83)
# print(p1.BMI)
# print(p1.name)
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存放到真实的位置self.__NAME
    @name.deleter
    def name(self):
        raise PermissionError('Can not delete')
obj = Foo('jason')
# print(obj.name)
# obj.name = 666
# print(obj.name)
del obj.name

面向对象三大特性之多态

多态:一种事物的多种形态
 	水:液态 气态 固态
 	动物:人 狗 猫 猪
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.miao()
# d1.wang()
# p1.heng()
"""
一种事物有多种形态 但是相同的功能应该有相同的名字
这样的话 以后我无论拿到哪个具体的动物 都不需要管到底是谁 直接调用相同的功能即可
    无论你是鸡 鸭 猫 狗 猪 只要你想叫 你就调固定的叫的功能
"""
# c1.spark()
# d1.spark()
# p1.spark()

"""
其实上述多态的概念 我们很早之前就已经解除过
"""
# l1 = [11, 22, 33, 44]
# d1 = {'name': 'jason', 'pwd': 123, 'hobby': 'raed'}
# t1 = (11, 22, 33, 44)
# print(len(l1))
# print(len(d1))
# print(len(t1))
"""
python也提供了一种强制性的操作(了解即可)  应该是自觉遵守
"""
# import abc
# # 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
# class Animal(metaclass=abc.ABCMeta):
#     @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
#     def talk(self): # 抽象方法中无需实现具体的功能
#         pass
# class Person(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
#     def talk(self):
#         pass
#     def run(self):
#         pass
# obj = Person()

"""
鸭子类型
    只要你长得像鸭子 走路像鸭子 说话像鸭子 那么你就是鸭子
"""
# class Teacher:
#     def run(self):pass
#     def eat(self):pass
# class Student:
#     def run(self):pass
#     def eat(self):pass
"""
操作系统
    linux系统:一切皆文件
        只要你能读数据 能写数据 那么你就是文件
            内存
            硬盘
        class Txt: #Txt类有两个与文件类型同名的方法,即read和write
            def read(self):
                pass
            def write(self):
                pass
        
        class Disk: #Disk类也有两个与文件类型同名的方法:read和write
            def read(self):
                pass
            def write(self):
                pass
        
        class Memory: #Memory类也有两个与文件类型同名的方法:read和write
            def read(self):
                pass
            def write(self):
                pass
    python:一切皆对象
        只要你有数据 有功能 那么你就是对象
            文件名         文件对象
            模块名         模块对象       
"""

面向对象之反射

反射: 通过字符串来操作对象的数据或方法
反射主要就四个方法
hasattr(): 判断对象是否含有某个字符串对应的属性
getattr(): 获取对象字符串对应的属性
setattr(): 根据字符串给对象设置属性
delattr(): 根据字符串给对象删除属性
class Student:
    school = '清华大学'

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


stu = Student()
需求:判断用户提供的名字在不在对象可以使用的范围内
方式1:利用异常处理(过于繁琐)
try:
    if stu.school:
        print(f"True{stu.school}")
except Exception:
    print("没有属性")
"""
变量名school 与字符串school 区别大不大
    stu.school
    stu.'school'
两者虽然只差了引号 但是本质是完全不一样的
"""
# 方式2:获取用户输入的名字 然后判断该名字对象有没有
while True:
    target_name = input('请输入您想要核查的名字>>>:').strip()
    '''上面的异常更加不好实现 需要用反射'''
    # print(hasattr(stu, target_name))
    # print(getattr(stu, target_name))
    if hasattr(stu, target_name):
        # print(getattr(stu, target_name))
        res = getattr(stu, target_name)
        if callable(res):
            print('拿到的名字是一个函数', res())
        else:
            print('拿到的名字是一个数据', res)
    else:
        print('不好意思 您想要查找的名字 对象没有')
print(stu.__dict__)
stu.name = 'jason'
stu.age = 18
print(stu.__dict__)
setattr(stu, 'gender', 'male')
setattr(stu, 'hobby', 'read')
print(stu.__dict__)
del stu.name
print(stu.__dict__)
delattr(stu, 'age')
print(stu.__dict__)
"""
以后只要在需求中看到了关键字
	....对象....字符串 
那么肯定需要使用反射
"""

反射实战案例

class FtpServer:
    def serve_forever(self):
        while True:
            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()
posted @   初学者-11  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示