博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
9.3 元类
阅读量:4664 次
发布时间:2019-06-09

本文共 3454 字,大约阅读时间需要 11 分钟。

9.3 元类

一、元类的定义

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

class Person:    passp=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=namedef score(self):    print('分数是100')''',{},l)People = type('People',(object,),l)p=Person('nick')print(p.name)        # nickprint(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(
,){'__module__': '__main__', '__qualname__': 'Person', '__doc__': '\n 注释\n ', 'school': 'oldboy', '__init__':
, 'score':
}'''

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

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 objclass 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继承关系去父类中找--->报错

1036857-20180715025321555-1883441972.png

转载于:https://www.cnblogs.com/dadazunzhe/p/11455356.html

你可能感兴趣的文章
Neat Tooltip for ComboBox(VC++)
查看>>
计划产量导入功能修改:
查看>>
python -- IO多路复用
查看>>
(转)web.xml中的contextConfigLocation在spring中的作用
查看>>
Foundation和UIKit框架组织图
查看>>
如何在Mac的Finder中显示/usr,/tmp,/var等隐藏目录
查看>>
rpm package.http://rpmfind.net/
查看>>
js 将网页内容生成图片
查看>>
批处理延时启动程序
查看>>
获取本目录及子目录下所有文件
查看>>
IDEA中的version control问题
查看>>
php单元测试/涉及代码覆盖率——netbeans工具
查看>>
域名解析
查看>>
学习嵌入式开发板的Android平台体系结构和源码结构
查看>>
变量类型的定义
查看>>
java_实现Hello World
查看>>
DEMO程序 排序
查看>>
15-算法训练 P1103
查看>>
Latent semantic indexing【转】
查看>>
FCL研究-目录
查看>>