zoukankan      html  css  js  c++  java
  • 元类

    反射 reflect:
    反射 其实不是我们字面意思的折射,而是反省,自检的意思
    反射指的是一个对象应具备,可以检测,修改,增加自身属性的能力
    反射就是通过字符串操作属性
    涉及了四个函数,这四个函数其实就是普通的内置函数,没有双下划线
    和print() len()一样没有什么其他的特殊区别
    这四个函数分别是:
    hasattr: 判断某个对象是否存在某种属性
    getattr: 从对象中获取属性,第三个值为默认值,当属性不存在时返回默认值
    setattr: 往对象里面添加新的属性
    delattr: 从对象里面删除属性
    实例:
    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    p = Person("哨兵", 18)
    # print(p.name)
    if hasattr(p,"name"):
        print("对象P里面存在'name'这个属性") # >>>对象P里面存在'name'这个属性
        print(getattr(p,'age',None))   # 执行结果>>>哨兵  最后的返回值None属性存在时不写也可以
        print(getattr(p, 'asd',None))  #  当属性不存在时,会返回None,如果这个时候没有写None会报错
    setattr(p,"id",23456)  # setattr 为对象添加新的属性
    setattr(p,"age",23456) # 当属性存在时,会覆盖老的值
    print(p.age)
    
    delattr(p,"age")  # 从对象里面删除指定的值
    print(p.age)   #>>>  AttributeError: 'Person' object has no attribute 'age'
    

      



    使用场景:
    反射其实就是对属性的增删改查,但是如果直接使用内置的dict来操作,语法繁琐,而且不便于阅读理解
    另外最重要的问题是:
    如果对象不是我们自己写的是另外一方提供的,那么我们就要必须判断这个对象是否可以满足我们的需求
    也就是说是否使我们所需要的属性和方法
    框架设计方式:
    框架代码:
    #反射的四个函数实例:
    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    p = Person("哨兵", 18)
    # print(p.name)
    if hasattr(p,"name"):
        print("对象P里面存在'name'这个属性") # >>>对象P里面存在'name'这个属性
        print(getattr(p,'age',None))   # 执行结果>>>哨兵  最后的返回值None属性存在时不写也可以
        print(getattr(p, 'asd',None))  #  当属性不存在时,会返回None,如果这个时候没有写None会报错
    setattr(p,"id",23456)  # setattr 为对象添加新的属性
    setattr(p,"age",23456) # 当属性存在时,会覆盖老的值
    print(p.age)
    
    delattr(p,"age")  # 从对象里面删除指定的值 
    print(p.age)   #>>>  AttributeError: 'Person' object has no attribute 'age'
    '''
    """
    

      



    反射被称之为框架基石,因为框架的设计者不可能提前知道你的对象到底是怎么设计的
    所以你提供框架的对象,必须通过判断验证之后才可以正常使用,而3判断和验证就是反射需要做的事情
    当然也可以使用__dict__来实现,期是这种方法就是把__dict__的操作进行了封装
    实例说明:
    需求: 要实现一个用于处理用户终端指令的模拟小框架
    首先分为框架部分
    插件部分
    配置文件部分
    #框架部分:
    import importlib
    import settings
    
    def run(plugin):
        while True:
            cmd = input("请输入命令").strip()
            if cmd == "exit":
                break
            if hasattr(plugin,cmd): # 判断对象是否具有处理这个指令的方法
                # 如果有
                func = getattr(plugin,cmd)
                func()
            else:
                print("该指令不存在")
        # print("see you la la ")
        return "hahaha"
    
    path = settings.CLASS_PATH
    # 从配置文件setings中拿到模块的路径和类的名字
    module_path, class_name = path.rsplit(".",1)
    #拿到模块
    lk = importlib.import_module(module_path)
    # 拿到类
    cls = getattr(lk,class_name)
    res = cls()
    run(res)
    
    配置文件部分settings文件
    ###这个文件作为框架的配置文件###
    CLASS_PATH = "lib.plugins.LinuxCMD"
    插件部分在LIB文件下的plugins
    
    
    属于插件部分
    
    class WinCMD:
        def cd(self):
            print("wincod 切换目录")
    
        def delete(self):
            print("wincod 删除文件")
    
        def dir(self):
            print("wincod 列出所有文件")
    class LinuxCMD:
    
        def cd(self):
            print("Linuxcmd 切换目录....")
    
        def rm(self):
            print("Linuxcmd 要不要删库跑路?")
    
        def ls(self):
            print("Linuxcmd 列出所有文件....")
    

      


    元类:
    元类就是用于创建类的类,也就是原始类,大多数情况下都是type
    万物皆对象,类也就是对象了,那么对象是有类实例化产生的,那么类也就是
    另一个类实例化产生的,所以说默认情况下所有的类元类就是TYPE
    #元类验证实例
    class A:
    pass
    a = A()
    print(type(a)) # a 的元类是 <class '__main__.A'>
    print(type(A)) # A 的元类是 <class 'type'>

    学习元类的目的:
    高度自定义一个类,类也是对象,也有自己的类也就是元类
    我们可以对类创建对象多一些限制,那么我们就可以在初始化上面做一些手脚
    只要我们找到类对象的元类,覆盖其中的__init__方法就可以实现
    因为我们不能修改源代码,所以我们应该是用继承元类的方式来编写自己,同时
    覆盖__init__来实现
    元类的实例
    '''
    直接调用元类type类来产生对象
    cls = type("泰迪",(),{})
    print(cls)
    一个类的三个基本组成部分
    1.类的名字(字符串类型的)
    2.父类的名字(列表或者元祖组成)
    3.类的名称空间(字典类型)
    
    '''
    

      

    class MyTypt(type):
        def __init__(self,class_name,bases, dict ):
            super().__init__(class_name,bases, dict) # 元类的__init__方法
            print(class_name,bases, dict)
            if not class_name.istitle(): # 限制类的首字母大写
                raise Exception("类名请单词首字母大写")
    class Dig(metaclass=MyTypt):
        pass
    
    class Duck(metaclass=MyTypt):
        pass
    
    class ds(metaclass=MyTypt):
        pass
    <   raise Exception("类名请单词首字母大写")
    Exception: 类名请单词首字母大写  >
    

      


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

    覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建
    并返回其返回值
    首先使用场景:
    想要控制对象的创造过程时需要使用__call__方法
    想要控制类创造过程中时候,就要覆盖__init__方法
    实例:
    class Da(type):
        def __call__(self, *args, **kwargs):
            new_args = []
            for i in args:
                new_args.append(i.upper())
            print(new_args)
            print(kwargs)
            return super().__call__(*new_args,**kwargs)
    class Ap(metaclass=Da):
        def __init__(self, name, gender):
            self.name = name
            self.gender = gender
        # def __call__(self, *args, **kwargs):
    
    
    a = Ap("jack","n")
    print(a.name)
    print(a.gender)
    实例2:
    class Mate(type):
        def __call__(self, *args, **kwargs):
            if args:
                raise Exception("不好意思不能使用未知参数")
            return super().__call__(*args, **kwargs)
    
    class A(metaclass=Mate):
        def __init__(self,name ):
            self.name = name
    a = A(name = "jack")
    print(a.name)
    注意:一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象
    

      


    new的方法
    当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作
    注意:,如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象
    class Meta(type):
        def __new__(cls, *args, **kwargs):
            print(cls) # 元类自己
            print(*args) # 创建需要的几个参数,类名,基类,名称空间
            print(**kwargs) # 空的
            print("new_run")
            res = type.__new__(cls,*args,**kwargs)
            return res
        def __init__(self,a,b,c):
            super().__init__(a,b,c)
            print("init_run")
    class A(metaclass=Meta):
        pass
    print(A)
    

      


    总结new方法和init 都可以实现控制类的创建过程,init更简单

    单例涉及模式:
    设计模式,用于解决问题的方式的某种套路
    单例:指的是一个类产生一个对象
    为什要使用单例:
    单例是为了节省资源,当一个类的所有对象属性全部相同时,测没有必要创建多对象
    实例:
    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()    
    

      

  • 相关阅读:
    angular2
    angular1
    JavaScript随笔1
    鼠标样式
    清除浮动
    css-父标签中的子标签默认位置
    [Leetcode] Decode Ways
    [Java] 利用LinkedHashMap来实现LRU Cache
    LinkedHashMap和HashMap的比较使用(转)
    [Java] java.util.Arrays 中使用的 sort 采用的算法 (转)
  • 原文地址:https://www.cnblogs.com/ioipchina/p/11273340.html
Copyright © 2011-2022 走看看