1.派生方法实战演练

"""
背景:如何将字典d序列化成json格式?
"""
import json
import datetime

d = {
    't1': datetime.date.today(),
    't2': datetime.datetime.today(),
    't3': 'jason'
}
res = json.dump(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:手动转换,把字典的V转化成字符串
import json
import datetime

d = {
    't1': str(datetime.date.today()),
    't2': str(datetime.datetime.today()),
    't3': 'jason'
}

res = json.dumps(d)
print(res)  # {"t1": "2022-11-07", "t2": "2022-11-07 14:56:09.858723", "t3": "jason"}

转换方式2:派生方法
class MyJsonEncoder(json.JSONEncoder):
    def default(self, o):
        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(d, cls=MyJsonEncoder)
print(res)  # {"t1": "2022-11-07", "t2": "2022-11-07 15:04:11.130998", "t3": "jason"}    

2.面向对象三大特征之封装

封装:就是将数据和功能'封装'起来
隐藏:就是将数据和功能隐藏起来不让用户直接调用,而是开发一些接口间接调用,从而可以在接口内添加额外的操作
伪装:将类里面的方法伪装成数据,目的是调用方法可以像调用数据一样不用加括号

"""
隐藏类名称空间中名字的语法结构是在类的定义阶段名字前面加上__,那么通过类或者对象点名字的方式都无法直接找到这个名字,如果想要拿到语法结构为:类或对象._类名__名字
"""
class Myclass:
    school_name = '清华大学'
    _ = '嘿嘿嘿'
    _name = 'max'
    """
    类在定义阶段,名字前面有两个下划线,那么名字会被隐藏起来,无法直接访问
    """
    __age = 25
    """
    在python中,没有真正的隐藏,仅仅是换了个名字
    """
    def __choice_course(self):
        print('选课系统')
print(Myclass.school_name)  # 清华大学
obj = Myclass()
print(obj.school_name)  # 清华大学
print(Myclass._)  # 嘿嘿嘿
print(obj._)  # 嘿嘿嘿
print(Myclass._name)  # max
print(obj._name)  # max
print(Myclass.__age)  # 会报错,因为__被隐藏
print(Myclass._Myclass__age)  # 25
print(obj._Myclass__age)  # 25
Myclass.__gender = 'male'
print(Myclass.__gender)  # male  手动添加的类的名字无法隐藏
obj = Myclass()
obj.__addr = 'shanghai'
print(obj.__addr)  # shanghai  手动添加对象的名字无法隐藏



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('max', 25, 'fitness')
obj.get_info()

obj.set_name('jack')
obj.get_info()

"""
如果用__dict__查看对象名称空间,发现字典中所有的键都变成了:_类名__名字
"""

"""
以后我们在编写面向对象代码类的定义是,也会看到很多单下划线开头的名字,表达的意思通常是不要直接访问,而是查找一下下面可能定义的接口
"""

3.伪装

"""
类中有的功能返回值是一个数字,而我们调用的时候仍需要像调用函数一样调用,此时可以通过@property来装饰功能,使被装饰的功能从调用方式上来说更像一个数据
"""
BMI指数:衡量一个人的体重与身高对健康影响的一个指标
BMI=体重(kg)÷身高^2(m)

class Person(object):
    def __init__(self, name, height, weight):
        self.name = name
        self.height = height
        self.weight = weight

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

p1 = Person('max', 1.82, 70)
print(p1.BMI())  # 21.132713440405748

有了@property之后功能BMI更像是一个数据,但是用该方法伪装不能加参数
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('max', 1.82, 70)
print(p1.BMI)  # 21.132713440405748

"""
当用property修饰之后的函数无法用对象名点名字的方式修改,此时用@函数名.setter修饰一个修改的函数,用户可以直接用对象名点的方式来修改
"""
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必须是字符串' % value)
        self.__NAME = value

	 @name.deleter
    def name(self):
        raise PermissionError('Can not delete')

f1 = Foo('jason')
print(f1.name)  # jason
f1.name = 'max'  # 触发name.setter装饰器对应的函数
print(f1.name)  # max
del f1.name  # PermissionError: 不能被删除
# 触发name.deleter对应的函数name(f),抛出异常PermissionError

4.三大特性之多态

1.多态:多态是指一种食物可以有多种形态但是针对相同的功能应该设定相同的方法,这样无论我们拿到的是哪个具体事务,都可以通过相同的方法调用功能(多态类型下父类的功能不再是为了省代码,而是提示每一个子类如果想要达成相同的目的必须要有相同的方法)
class Animal:
    def spark(self):
        pass
    
def Cat(Animal):
    def spark(self)
    print('喵喵喵')
    
def Dogs(Animal):
    def spark(self)
    print('汪汪汪')
    
def Pig(Animal):
    def spark(self)
    print('哼哼哼')
"""
面向对象中多态意思是,一种事物可以有多种形态但是针对相同的功能应该定义相同的方法,这样无论我们拿到的是哪个具体的事物,都可以通过相同的方法调用功能
"""
s1 = 'hello world'
l1 = [11, 22, 33, 44]
d = {'name': 'jason', 'pwd': 123}
print(s1.__len__())
print(l1.__len__())
print(d.__len__())

2.鸭子类型:只要你看上去像鸭子,走路像鸭子,说话像鸭子,那么你就是鸭子。以linux系统为例,文件能够读取数据也可以保存数据,内存能够读取数据也能保存数据吧,硬盘能够读取数据也能保存数据,所以在linux中有句话叫一切皆文件
eg:
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

5.面向对象至反射

反射:利用字符串操作对象和数据的方法:
1.hasattr():
    判断对象是否含有某个字符串对应的属性名或方法名
2.getattr():
    根据字符串获取对象对应的属性名(数据)或方法(函数体代码)
3.setattr():
    根据字符串给对象设置或者修改数据
4.delattr():
    根据字符串删除对象里面的名字
"""
判断某个名字对象是否存在
"""
class School:
    school_name = '小姐姐学院'
    def choice_course(self):
        print('选课系统')
obj = School

try:
    obj.school_name
except Exception:
    print('没有这个名字')   
else:  # try的子代码为True时走else子代码
    print('名字存在哦') 
#  执行结果:名字存在哦

"""
请结合用户输入,查看用户输入的名字是否存在
"""
class School:
    school_name = '小姐姐学院'
    def choice_course(self):
        print('选课系统')
obj = School

target_name = input('请输入您想查看的名字>>>:').strip()

try:
    obj.target_name
except Exception:
    print('没有这个名字')
else:
    print('名字存在哦')
#  执行结果:没有这个名字
"""
因为获取用户输入得到的是字符串,而对象点的是变量名。反射的作用就是利用字符串操作对象的数据和方法
"""
print(hasattr(obj, 'school_name'))  # True
print(getattr(obj, 'school_name'))  # 小姐姐学院
print(getattr(obj, 'choice_course'))  # <function School.choice_course at 0x0000020D15538598>

"""
hasattr和getattr找对象的数据和方法首先从对象名称空间中找,其次从产生对象的类名称空间中找,找不到再去父类名称空间中找
"""
class A:
    name = 'jason'

class B(A):
    pass

b = B()
print(getattr(b, 'name'))  # jason

"""
判断用户输入的名字是否存在,如果存在则执行
"""
class C1:
    school_name = '小姐姐学院'
    def choice_course(self):
        print('选课系统')

obj = C1()
while True:
    target_name = input('请输入您想要操作的名字>>>:').strip()
    if hasattr(obj, target_name):
        print('恭喜你,系统中有名字')
        data_or_func = getattr(obj, target_name)
        if callable(data_or_func):
            print('您本次执行的是系统中的方法')
            data_or_func()
        else:
            print('您本次执行的是系统中某个数据')
            print(data_or_func)
    else:
        print('系统当中未找到该名字')

6.反射实战案例

1.什么时候考虑使用:只要需求中出现关键字:对象...字符串...,用反射可以将获取用户输入和面向对象结合起来
        
2.实战案例:
class WinCmd:
    def tasklist(self):
        print("""
        1.学习编程
        2.学习理论
        """)

    def ipconfig(self):
        print("""
        addr:127.0.0.1
        """)

    def get(self, target_file):
        print('正在获取指定文件', target_file)

    def put(self, target_file):
        print('正在上传指定文件', target_file)

    def service_run(self):
        print('欢迎进入简易版cmd终端')
        while True:
            target_cmd = input('请输入您的指令>>>:').strip()
            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.service_run()

2.一切皆对象:文件也是对象,getattr/hasattr(obj, name)中的obj也可以换成文件名
需求一:利用反射保留某个py文件中所有的大写的变量名及对应的数据值
import settings

upper_dict = {}
for name in dir(settings):
    if name.isupper():
        upper_dict[name] = getattr(settings, name)

print(upper_dict)  # {'AGE': 25, 'NAME': 'max'}

需求二:找到settings中为大写的名字对应的值:
import settings
while True:
    target_name = input('请输入名字>>>:').strip()
    if hasattr(settings, target_name):
        print(getattr(settings, target_name))
    else:
        print('模块文件中暂无该名字')

原文地址:http://www.cnblogs.com/zkz0206/p/16867504.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性