• 面向对象高级部分


    一、反射

    1.什么是反射?

    反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力

    反射就是通过字符串操作属性

    主要涉及以下四个函数:

    hasattr getattr setattr delattr

    class Person:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    p = Person('jack',18)
    print(p.name,p.age)  # jack 18
    
    
    print(hasattr(p,'name'))  # 判断某个对象的属性是否存在某个属性;此处name在p中,所以返回结果为True
    
    
    print(getattr(p,'name',None))  # 从对象中取出属性,第三个值为默认值,当属性不存在时返回默认值
    
    
    setattr(p,'sex','man')  # 添加新的属性
    print(p.sex)  # 会将sex这个属性添加到p当中
      
      
    delattr(p,'age')  # 将从对象中删除属性
    print(p.age)  # 打印结果不存在,会报错

    2.使用场景:

    反射其实就是对属性的增删查改,但是如果直接使用内置的dict来操作,语法繁琐,不好理解

    另外一个最主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须判断这个对象是否满足的要求,也就是是否我需要的属性和方法

    框架设计方式:

    框架代码:

    反射被称为框架的基石,为什么 因为框架的设计者,不可能提前知道你的对象到底是怎么设计的 所以你提供给框架的对象 必须通过判断验证之后才能正常使用 判断验证就是反射要做的事情, 当然通过dict也是可以实现的, 其实这些方法也就是对dict的操作进行了封装

     

    二、元类

    1.元类是什么?

    它是用于创建类的类,类也是一个对象

    对象是通过类实例化产生的,既然类也是对象,那么类对象也是由另一个类实例化产生的

    默认情况下所有累的元类都是type

    2.验证:

    class Person:
        pass
    p = Person()
    
    print(type(p))  # <class '__main__.Person'>
    print(type(Person))  # <class 'type'>
    
    Person类是通过type类实例化产生的

    3.学习类的目的

    高度的自定义一个类,例如控制类的名字必须以大驼峰的方式来书写

    类也是对象,也有自己的类,

    我们的需求是创建类对象做一些限制

    想到了初始化方法 我们只要找到类对象的类(元类),覆盖其中 init方法就能实现需求

    当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求

    代码:

    只要继承了type,那么这个类就变成了一个元类
    定义一个类
    class MyType(type):
        def __init__(self,class_name,bases,dict):
            super().__init__(class_name,bases,dict)
            print(class_name,bases,dict)
            if not class_name.istitle():
                raise Exception('类名错误')
    
    class pig(metaclass=MyType):
        pass
    
    class Duck(metaclass=MyType):
        pass

    4.元类中call的方法

    当调用类对象时会自动启动元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数

    覆盖元类中的call之后,这个类就无法产生对象,必须调用super().call来完成对象的创建 并返回其返回值

    使用场景:

    当想要控制对象的创建过程时,就覆盖call方法

    当想要控制类的创建过程时,就覆盖init方法

    例题:

    实现将对象的所有属性名称转为大写

    class MyType(type):
        def __call__(self, *args, **kwargs):
            new_args = []
            for a in args:
                new_args.append(a.upper())
    
                print(new_args)
                print(kwargs)
                return super().__call__(*new_args,**kwargs)
    
    
    class Person(metaclass=MyType):
        def __init__(self,name,gender):
            self.name = name
            self.gender = gender
    
    p = Person(name="jack",gender="woman")
    print(p.name)
    print(p.gender)

    注意:一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象

    5.补充new方法

    当要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作 注意:,如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象

    6.单例设计模式

    单例:指的是一个类产生一个对象

    设计模式:是用于解决某种固定问题的套路

    单例的作用:能够节省资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象

    # 单例n元类
    class Single(type):
        def __call__(self, *args, **kwargs):
            if hasattr(self,"obj"): #判断是否存在已经有的对象
                return getattr(self,"obj") # 有就返回
    
            obj = super().__call__(*args,**kwargs) # 没有则创建
            print("new 了")
            self.obj = obj # 并存入类中
            return obj
    
    
    class Student(metaclass=Single):
        def __init__(self,name):
            self.name = name
    
    
    class Person(metaclass=Single):
        pass
    
    # 只会创建一个对象
    Person()
    Person()

    三、冒泡排序的补充

    将此列表从大到小进行排序
    s = [2,1,3,5]
    第一圈:
    [2,1,3,5]
    第一次 得出2的位置
    [2,1,3,5]
    第二次
    [2,3,1,5]
    第三次
    [2,3,5,1]
    
    次数为  元素个数 - 1 - (圈数索引为0)
    
    
    第二圈:
    [2,3,5,1]
    第一次
    [3,2,5,1]
    第二次
    [3,5,2,1]
    
    次数为 元素个数 - 1 - (圈数索引为1)
    
    第三圈:
    [3,5,2,1]
    第一次 
    [5,3,2,1]
    
    次数为 元素个数 - 1 - (圈数索引为2)
     总结规律
    圈数 是元素个数减一
    次数 元素个数 - 1 - (圈数索引)
    我们需要两层循环
    一层控制圈数
    一层控制次数
    冒泡排序的模板
    s = [2,1,3,5,100,24,12,12,1,2,1,1,4,32]
    for i in range(len(s)-1):
        for j in range(len(s)-1-i):
            # 如果前面的小于后面的则交换位置
            if s[j] > s[j+1]:
                s[j],s[j+1] = s[j+1],s[j]
    print(s)
    
    
    
     







  • 相关阅读:
    走读OpenSSL代码从一张奇怪的证书说起(二)
    从数学到密码学(十八)
    从数学到密码学(十七)
    走读OpenSSL代码从一张奇怪的证书说起(一)
    从数学到密码学(十六)
    从数学到密码学(十五)
    从数学到密码学(十三)
    从数学到密码学(十九)
    从数学到密码学(十四)
    关于Terracotta DSO 安装
  • 原文地址:https://www.cnblogs.com/xiongying4/p/11271911.html
Copyright © 2020-2023  润新知