反射及元类

反射

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

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

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

涉及的四个函数,这四个函数就是普通的内置函数 没有双下划綫,与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__)
原文地址:https://www.cnblogs.com/asdaa/p/11273213.html