zoukankan      html  css  js  c++  java
  • 反射及元类

    反射

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

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

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

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

    class Person:
        def __init__(self,name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    
    p = Person('cly', 17, 'female')
    
    print(hasattr(p, 'salary'))  # 判断对象中是否存在某个属性
    print(getattr(p, 'ages', None))  # 从对象中取出属性,第三个值位默认值 当属性不存在是返回默认值
    
    # 为对象添加属性
    setattr(p, 'salary', 1000000000)
    
    # 删除对象属性
    delattr(p, 'salary')

    使用场景:

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

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

    元类 metaclass

    所有的类都是对象

    所有的类都是元类产生的

    object是根类,是所有类的父类

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

     

    学习元类的目的:

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

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

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

    我们可以找到类对象的类(元类)进行覆盖其中init方法就能实现需求

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

    # 继承type元类
    # 定义了一个类
    class A(type):
        def __init__(self,class_name,bases,dict):
            super().__init__(class_name,bases,dict)
            self.name = class_name
            if not self.name.istitle():
                raise Exception
    # 为asd类指定了元类为A
    class asd(metaclass=A):
        pass

    元类中call方法

    当你调用类对象时会自动珍惜元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数
    
    覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建  
    并返回其返回值 

    使用场景

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

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

    案例:

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

    class Mytype(type):
        def __call__(self, *args, **kwargs):
            l = []
            for i in args:
                l.append(i.upper())
            return super().__call__(*l, **kwargs)
    
    
    class Person(metaclass=Mytype):
        def __init__(self, name, gender):
            self.name = name
            self.gender = gender
    
    p = Person('cly','man')
    print(p.__dict__)

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

     

    补充new方法

    当你要创建对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用
    __init__来对这个类进行初始化操作
    注意:如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是对应的类对象
    class Meta(type):
    
        def __new__(cls, *args, **kwargs):
            print(cls) # 元类自己
            print(args) # 创建类需要的几个参数  类名,基类,名称空间
            print(kwargs) #空的 
            print("new run")
            # return super().__new__(cls,*args,**kwargs)
            obj = type.__new__(cls,*args,**kwargs)
            return obj
        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 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 Person(metaclass=Mytype):
    
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    p = Person('cly', 18)
    p1 = Person('asd','asd')
    # 只会存在一个对象
    print(p1.__dict__)
  • 相关阅读:
    python中numpy的用法
    基于逻辑回归识别坐标是否在第一象限
    python变量,函数
    DOM的核心总结
    节点操作
    自定义属性操作
    排他思想及部分案例
    事件基础及操作元素
    获取元素
    DOM 介绍
  • 原文地址:https://www.cnblogs.com/asdaa/p/11273213.html
Copyright © 2011-2022 走看看