面向对象元类介绍 以及反射

1 元类

1 定义

元类: 用于产生类的类 称之为元类

元类翻译为:metaclass 只要看见它就应该想起来这是元类

 

我们在定义元类时 尽量在类名后添加MetaClass 方便阅读

一切皆对象

类也是对象,可以把一个类当成普通对象来使用,比如存储到列表中,或者作为参数传给函数等等...

对象是如何产生的? 通过类实例化产生的

类对象 是由type实例化产生的

class AClass:
    pass
print(type(AClass)) # <class 'type'>

  

2 类的三大组成部分

1.类的名称 我是谁

2.类的父类们 我从哪里来

3.类的名称空间 我有什么

 

我们可以手动调用type来实例化产生一个类 

type(类名,父类元组,名称空间字典)  #返回一个新的类

type(对象)  #将会返回这个对象的类型

3 元类的运用

class MyMetaClass(type):
    pass

# 使用自定义元类
class Person(metaclass=MyMetaClass):
    pass

  

 

4 元类中的__init__运用

实例化对象时会自动执行类中的`__init__`方法, 类也是对象 ,在实例化类对象时会自动执元类中的`__init__`方法

并且传入类的三个必要参数,类的名字,父类们,名称空间

当然会自动传入类对象本身作为第一个参数  

 

案例:案例: 限制类名必须首字母大写 控制类中方法名必须全部小写

 
class MyMetaClass(type):
    def __init__(self,class_name,bases,name_dict):

        super().__init__(class_name,bases,name_dict)  # 子类重用父类中的方法
        # 类名必须首字母大写  否则直接抛出异常
        if not class_name.istitle():
            print("类名必须大写 傻x!")
            raise Exception

        # 控制类中方法名必须全部小写
        for k in name_dict:
            if str(type(name_dict[k])) == "<class 'function'>":
                if not k.islower():
                    raise Exception
    pass



# 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们  名称空间
class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{})
    NAME = 10
    def say(self):
        print("SAY")
    pass


# 解释 class Student() 类 如果类名首字母不是大写就会报错   如果方法不是小写就会报错

 

5 元类中的__new__方法

 

元类中的new方法会在创建类对象时执行,并且先于init方法

作用是创建一个类对象

class A(metaclass=MyMetaClass):

pass

1.执行MyMetaClass的__new__方法 拿到一个类对象

2.执行MyMetaClass的__init__ 方法 传入类对象以及其他的属性 ,进行初始化

 

注意:如果覆盖了__new__ 一定也要调用type中的__new__并返回执行结果

使用new方法也可以完成定制类的工作 和init有什么区别?

在调用init方法前类对象已经创建完成了

所以如果对性能要求高的话 可以选在在new中完成定制 如果发现有问题,就不用创建类对象了

 

需求: 要求每个类必须包含__doc__属性

class DocMeatClass(type):

    def __init__(self,class_name,bases,name_dict):
        super().__init__(class_name,bases,name_dict)
        # if not("__doc__" in name_dict and name_dict["__doc__"]):
        #     raise  Exception
        
        # 或者如下
        if not self.__doc__:
            raise Exception

class Person(metaclass=DocMeatClass):
    """"""
    pass

  

# 需求: 要求每个类必须包含__doc__属性   __doc__ 用于访问一个对象的注释信息


# 你要控制类的创建  那就自定义元类 覆盖__init__
class DocMeatClass(type):

    def __init__(self,class_name,bases,name_dict):
        super().__init__(class_name,bases,name_dict)
        # if not("__doc__" in name_dict and name_dict["__doc__"]):
        #     raise  Exception
        if not self.__doc__:
            raise Exception

class Person(metaclass=DocMeatClass):
    pass

  

 

6 元类中的__call__方法(重点)

元类中的 call方法会在调用类时执行,

可以用于控制对象的创建过程

  

class MyMeta(type):

    # 获得某个类的实例
    def __call__(self, *args, **kwargs):
        print("call")
        # return super().__call__(*args,**kwargs)
        new_args = []
        for i in args:
            if isinstance(i,str):
                new_args.append(i.upper())
            else:
                new_args.append(i)
        return super().__call__(*new_args,**kwargs)



# 注意注意注意:  __new__  __init__ 是创建类对象时还会执行
# __call__ 类对象要产生实例时执行

class Student(metaclass=MyMeta):
    def __init__(self,name,gender,age):
        self.name = name
        self.gender = gender
        self.age = age

s = Student("jack","woman",18)
print(s.age)
print(s.gender)


class Person(metaclass=MyMeta):
    def __init__(self,name,gender):
        self.name = name
        self.gender = gender

p = Person("rose","man")
print(p.name)

 

总结:当你要定制类时,就自定义元类并覆盖init方法

 

7 元类实现单例模式

 

什么是单例:

某个类如果只有一个实例对象,那么该类成为单例类

单例的好处:

当某个类的所有对象特征和行为完全一样时,避免重复创建对象,浪费资源

案例:

class SingletonMetaClass(type):
    #创建类时会执init 在这为每个类设置一个obj属性 默认为None
    def __init__(self,a,b,c):
        super().__init__(a,b,c)
        self.obj = None
    
    # 当类要创建对象时会执行 该方法
    def __call__(self, *args, **kwargs):
         # 判断这个类 如果已经有实例了就直接返回 从而实现单例
        if self.obj:
            return self.obj

        # 没有则创建新的实例并保存到类中
        obj = type.__call__(self,*args,**kwargs)
        self.obj = obj
        return obj

    

2 反射

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

 

英文中叫反省 (自省)

面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力;

一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性

涉及到的方法:

hasattr 判断是否存在某个属性

getattr	获取某个属性的值

setattr	新增或修改某个属性 

delattr 删除某个属性 

 

案例:

class MY_CMD:

    def dir(self):
        os.system("dir")

    def ipconfig(self):
        os.system("ipconfig")

cmd = MY_CMD()

while True:
    name = input("请输入要执行的功能:")
    if hasattr(cmd,name):
        method = getattr(cmd,name)
        print(method)
        method()
    else:
        print("sorry this method is not exists....!")

  

 

 

原文地址:https://www.cnblogs.com/wakee/p/10891757.html