zoukankan      html  css  js  c++  java
  • 元类

    元类

    一、元类的定义

    python中一切皆对象,类也是一个对象,那么,创建类的是什么呢?

    class Person:
        pass
    p=Person()
    

    Person类也是一个对象,那它一定也是由一个类实例化得到的,那么这个类就叫元类

    type是内置的一个元类,所有的类都是由type实例化得到的。

    总结:元类就是产生类的类!

    二、class底层原理分析

    class 类名 : class关键字会把类构造出来。

    实际上,内部是由元类(type)实例化产生这个类的。

    怎么产生的呢,就是用type()传入一堆参数,实现的。

    语法

    type()
    type(object_or_name, bases, dict)
        object_or_name:类的名字,是个字符串
        bases:是它的所有父类,基类
        dict:名称空间,是一个字典
    

    通过type()创建一个类,不适用class关键字。

    l={}
    exec('''
    school='oldboy'
    def __init__(self,name):
        self.name=name
    def score(self):
        print('分数是100')
    ''',{},l)
    People = type('People',(object,),l)
    
    p=Person('nick')
    print(p.name)        # nick
    print(p.__dict__)    # {'name': 'nick'}
    

    exec()

    exec 执行储存在字符串或文件中的 Python 语句,相比于 eval,exec可以执行更复杂的 Python 代码。

    exec(object[, globals[, locals]])
    
    • object:必选参数,表示需要被指定的Python代码。它必须是字符串或code对象。如果object是一个字符串,该字符串会先被解析为一组Python语句,然后在执行(除非发生语法错误)。如果object是一个code对象,那么它只是被简单的执行。
    • globals:可选参数,表示全局命名空间(存放全局变量),如果被提供,则必须是一个字典对象。
    • locals:可选参数,表示当前局部命名空间(存放局部变量),如果被提供,可以是任何映射对象。如果该参数被忽略,那么它将会取与globals相同的值。

    返回值:exec 返回值永远为 None。

    通过元类来控制类的产生

    自定义元类来控制类的产生,可以控制类名,类的继承关系以及类的名称空间!

    type:自定义元类必须继承type,继承了type的类都叫元类。

    class Mymeta(type):
        def __init__(self,name,bases,dic):
            # 此时的self为Person这个类(Person类也是对象)
            print(name)
            print(bases)
            print(dic)
            
    # metaclass=Mymeta  指定这个类生成的时候,用自己写的Mymeta这个元类
    class Person(object,metaclass = Mymeta):
        school='oldboy'
        def __init__(self,name):
            self.name=name
        def score(self):
            print('分数是100')
    p = Person('nick')
    '''
    Person
    (<class 'object'>,)
    {'__module__': '__main__', '__qualname__': 'Person', '__doc__': '
        注释
        ', 'school': 'oldboy', '__init__': <function Person.__init__ at 0x03C0B4B0>, 'score': <function Person.score at 0x03C0B4F8>}
    '''
    

    练习:控制类名必须全大写,控制类必须加注释!

    class Mymeta(type):
        def __init__(self,name,bases,dic):
            # 此时的self为Person这个类(Person类也是对象)
            if not name.isupper():
           		raise Exception('类名必须全大写 。')
            doc = self.__dict__['__doc__']
        	if not doc:
                raise Exception('你的类没有加注释')
            
    # metaclass=Mymeta  指定这个类生成的时候,用自己写的Mymeta这个元类
    class Person(object,metaclass = Mymeta):
        school='oldboy'
        def __init__(self,name):
            self.name=name
        def score(self):
            print('分数是100')
    p = Person('nick')
    

    通过元类控制类的调用过程

    控制类的调用过程,实际上是在控制对象的产生。

    class Mymeta(type):
        # Person('nick') 自动触发init,先触发元类的__call__
        def __call__(self, *args, **kwargs):
            return self.__dict__  # 返回的是People类的对象p,无法点出属性/方法。
    
    class Person(object,metaclass=Mymeta):
        school='oldboy'
        def __init__(self,name):
            self.name=name
        def score(self):
            print('分数是100')
    
    p=Person('nick')
    print(p)
    

    练习:把对象中的所有属性设置成私有的

    class Mymeta(type):
        def __call__(self, *args, **kwargs):
            # 实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象
            obj=object.__new__(self)  # obj 是Person类的对象,只不过是空的
            # 对象调用__init__方法完成初始化
            obj.__init__(*args, **kwargs)
    		# 修改对象属性为私有属性(拼接_*__*)
            obj.__dict__={ '_%s__%s'%(self.__name__,k):v for k,v in     			                            obj.__dict__.items()}
    
            return obj
    
    class Person(object, metaclass=Mymeta):
        school = 'oldboy'
        def __init__(self, name):
            self.name = name
        def score(self):
            print('分数是100')
            
    p = Person(name='nick')
    print(p.__dict__)  # {'_Person__name': 'nick'}
    print(p.name)	   # AttributeError: 'Person' object has no attribute 'name'
    

    有了元类之后的属性查找顺序

    类的属性查找顺序:类自身-->按mro继承关系顺序去父类找-->自定义元类中找-->type-->报错

    对象的查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错

  • 相关阅读:
    QuotationTools自动化脚本的部署和使用
    QuotationTool能做什么.
    【计算机原理】CPU部分.md
    【计算机原理】程序执行过程
    【大话存储II】学习笔记(18章),数据前处理和后处理
    【大话存储】学习笔记(17章),数据容灾
    【大话存储】学习笔记(20章),云存储
    【大话存储】学习笔记(16章),数据保护和备份技术
    【大话存储II】学习笔记(15章),NoSQL
    数据库(七),读写分离到CQRS
  • 原文地址:https://www.cnblogs.com/dadazunzhe/p/11455356.html
Copyright © 2011-2022 走看看