• 反射 reflect


    反射 reflect

    什么是反射, 其实是反省,自省的意思

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

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

    涉及的四个函数,这四个函数就是普通的内置函数 没有双下划綫,与print等等没有区别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class Preson:
        def __init__(self,name,age):
            self.name = name
            self.age = age
     
    p = Preson("joke",12)
    # 判断该类中是否有name和namexxx这个属性
    # 如果有就返回 True,如果没有就返回 False
    # print(hasattr(p,"name"))
    # print(hasattr(p,"namexxx"))
     
    # 取出该对象中的属性,如果有就返回值,如果没有就报错
    # print(getattr(p,"name"))
    # # print(getattr(p,"name.xsss"))
     
    # 将该对象添加一个属性
    # setattr(p,"id",123)
    # print(getattr(p,"id"))
     
    # 删除该对象的一个属性
    # 删除过后,再访问该属性,报错
    # delattr(p,"id")

    使用场景:

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

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

    框架设计方式:

    框架代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    import importlib
    import settings
     
    def run(user):
        while True:
            cwd = input("请输入指令")
            if cwd == "exit":
                break
                # 判断出入的类中是否有我们输入的这个方法
            if hasattr(user,cwd):
                # 将类中的方法通过这个方法取出来
                func = getattr(user,cwd)
                # 执行
                func()
            else:
                print("指令错误")
        print("。。。。。。")
     
     
    # 拿到用户给的路径,和模块
    path = settings.path
    # 将路径,和模块分隔开
    module_path,module_name = path.rsplit(".",1)
    # 通过这个调用这个方法,拿到路径对应的模块
    mk = importlib.import_module(module_path)
    # 然后通过模块拿到里面的类
    cls = getattr(mk,module_name)
    # 然后将类实例化
    obj = cls()
    # 将实例化对象,传给我们写好的框架
    run(obj) 

    用户提供的模块:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # 用户的类
     
    class Wind:
        def cd(self):
            print("----------cd---------")
     
        def de(self):
            print("----------del---------")
     
        def rm(self):
            print("----------rm---------")
     
     
     
     
    class Lniux:
        def cd(self):
            print("----------cd---------")
     
        def de(self):
            print("----------del---------")
     
        def rm(self):
            print("----------rm---------")

    用户将提供的代码的位置,和类名,写入我们规定好的配置文件中,注意;格式需要严格按照我们的要求书写

    1
    2
    # 用户告诉我们的路径,用字符串放在这个配置文件中
    path = "model.info.Wind"

    元类 metaclass

    元类是什么,用于创建类的类

    万物皆对象,类当然也是对象

    对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的

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

    学习元类的目的:

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

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

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

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

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

    元类中init方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 定义一个类,让它继承与元类type
    class MyType(type):<br># self 是类Pig这个类对象,class_name 是类的名字(注意,这个只是类的名字,不是对象,self传入的才是类对象) bases 是继承的父类以元组的形式,dict 是对象的属字典
        def __init__(self,class_name,bases,dict):
            # 我们重写了元类中的init方法,要调用父类中的init方法
            super().__init__(class_name,bases,dict)
            # 判断字符串是第一个字母是否是大写
            if not class_name.istitle():
                raise Exception("asdasdasd")
     
    class Pig(metaclass=MyType):
        pass

    元类中call方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class MyType(type):
     
        def __call__(self, *args, **kwargs):
            print(self)
            new_args = []
            for i in args:
                new_args.append(i.upper())<br>      # 注意,当我们重写了call方法,一定要返回元类中的call方法,,还需哟将我们改过的参数一并返回给元类,用来创建对象
            return super().__call__(*new_args,**kwargs)
     
     
     
    class Preson(metaclass=MyType):
        def __init__(self,name,age):
            self.name = name
            self.age = age
     
    p = Preson("jake","rose")
     
    print(p.name)
    print(p.age)

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

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

    注意,init方法也是将这个类本身传入第一个参数

     

    init与call使用场景:

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

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

    补充new方法

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class MyType(type):
        def __new__(cls, *args, **kwargs):
            obj = type.__new__(cls, *args, **kwargs)
            return obj
     
        def __init__(self,clss_name,bases,dict):
            super().__init__(clss_name,bases,dict)
            if not clss_name.istitle():
                raise Exception("asdasdasda")
     
     
    class A(metaclass=MyType):
        def __init__(self,name,age):
            self.name = name
            self.age = age
    # 当元类中有new方法,会直接调用new方法
    # 通过type.__new__得到一个空对象
    # 空对象会直接调用__init__方法
    # 修改类的创建方式
    # 应为第二个参数就会类的字符,我们可以通过类的支付来约束类
    # 首字母是否大写,如果不是,就抛出异常

    单例设计模式

    设计模式?用于解决某种固定问题的套路
    例如:MVCMTV等
    单例:指的是一个类产生一个对象
    为什么要使用单例:单例是为了节省 资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class MyType(type):
     
        def __call__(self, *args, **kwargs):
     
            if hasattr(self,"obj"):
                return getattr(self,"obj")
     
     
            obj = super().__call__(*args, **kwargs)
            self.obj = obj
            return obj
     
     
     
    class Student(metaclass=MyType):
        def __init__(self,name):
            self.name = name
     
     
    s1 = Student("jason")
    print(s1.name)
    s2 = Student("jason")
    print(s2.name)
    s3 = Student("jason")
    print(s3.name)
    s4 = Student("jason")
    print(s4.name)

    总结 

    所有的类都是元类的实例化对象

    我们所学的基于对象的所有方法都有用

    在init   nwe   call 中的self都是我们下面创建的类对象,这个类对象是元类的实例对象

  • 相关阅读:
    centos8.2安装nginx
    Centos8安装PostgreSQL
    PostgreSQL 安装时提示下载元数据失败
    MySQL8定时备份
    Centos8安装Docker
    Centos8安装中文字体
    Centos8源码安装libgdiplus
    MySQL拖拽排序
    MySQL8修改事务隔离级别
    MySQL启动问题
  • 原文地址:https://www.cnblogs.com/le-le666/p/11272690.html
Copyright © 2020-2023  润新知