• 元类介绍


    # 元类
    # 说python当中一切皆对象,
    # 用class关键字定义的类其实本质也是一个对象。
    # class Foo:
    # pass
    # 说Foo是一个对象的话,对象肯定是由一个类实例化而来的。
    # 也就是说在class的时候,调class关键字的时候,必然是这个关键字去调了一个类的类,类的类就称之为元类。
    # 就是调了一个元类加括号实例化,元类加括号的结果就是用class定义的类
    # class Foo: # Foo = 元类()
    # pass
    # 所以说元类就是负责产生类的那一个类,是类的老祖宗。

    # 1.什么是元类?
    # 在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象
    # 负责产生该对象的类称之为元类,即元类可以简称为类的类


    # 2.为何要用元类?
    # 什么情况下用元类?
    # 元类是负责产生类的,可以控制类的产生过程,还可以控制对象的产生过程。
    # 什么叫对象的产生过程?
    # class Foo:
    # pass
    # Foo()
    # 对Foo这个类的产生控制,以及对调用Foo的这个过程的控制,因为调用Foo的过程就是产生Foo对象的过程


    # 3.如何用元类

    # 3.1 需要储备几点知识
    # 第一点知识: exec()这个内置函数

    # exec()这个内置函数用来干什么的呢?
    # 将一个字符串中的代码提出出来运行一下

    # cmd = '''
    # x=1
    # y=2
    # print('我爱老婆杨静,哈哈哈')
    # '''
    # local_dic = {}
    # exec(cmd,)
    # 模拟的就是执行python代码的过程,会产生一个名字,必然往名称空间里面去丢
    # 名称空间的格式是以字典的形式展现的
    # 所以造两个名称空间,一个全局名称空间
    # 怎么查看全局的名称空间:
    # print(globals())
    # 造一个空字典
    # local_dic = {}
    # exec(第一个参数是你的字符串,第二个参数是你要引用的那个全局作用域(不需要定义个空字典就好了),第三个是local_dic)
    # exec(cmd,{},local_dic)
    # print(local_dic)
    # 会发生什么是呢?
    # exec会执行字符串中的代码,将执行过程中产生的名字都往local_dic = {}里面丢
    # exec干了一件事:给你一段代码,只要执行过程中产生名字都丢到一个名称空间字典里面去。
    # 函数也可以!!
    # 函数体代码提取出来
    # def func():
    # x= 1
    # y=2
    # print('杨静爱老公张仁国,哈哈哈')

    # cmd = '''
    # x = 1
    # y = 2
    # print('杨静爱老公张仁国,哈哈哈')
    # '''
    # func_dic = {}
    # exec(cmd,{},func_dic)
    #
    # print(func_dic)

    # 类也可以!!
    # 类体代码提取出来

    # cmd = '''
    # x=1
    # def func():
    # y = 2
    # '''
    # class_dic = {}
    # exec(cmd,{},class_dic)
    # print(class_dic)
    # 类体执行过程中产生的名字都丢到名称空间里面去了
    # 这是模拟了类创建过程中类定义阶段造名称空间那一步操作


    # 用这个功能干嘛使?
    # 可以用来模拟造名称空间这个过程。


    # 3.2创建类过程当中有几个关键的要素
    # 创建类的方法有两种
    # 第一种class关键字去创建,用的是默认的元类:type
    # class People():
    # country = 'china'
    # def __init__(self,name,age):
    # self.name = name
    # self.age = age
    #
    # def eat(self):
    # print('%s is eating'%self.name)

    # # 查看People的类是谁:
    # print(type(People))
    # # <class 'type'>
    #
    # print(People)
    # obj = People('zrg',24)
    # print(obj)
    # obj.eat()
    # print(type(obj))

    # 大前提:如果说类也是对象的话,那么用class关键字去创建类的过程也是一个实例化的过程
    # 该实例化的目的是为了得到一个类,调用的是元类
    # 调用的元类又分为两种:
    # 一种是默认的元类type
    # 另一种是自定义的

    # 默认的元类的造类的过程:
    # 类的名字 class_name
    # 类的基类 class_bases
    # 类的名称空间 class_dic
    #
    # class_name = 'People' #类名必须是字符串形式
    # class_bases = (object,) #不继承任何类默认就是object逗号才叫一个元组
    # class_dic = {} #最关键的最难得,类的名称空间一个字典的形式
    # 类的名称空间从何而来----->从类体的执行而来,而类体就是一堆字符串
    # class_body = '''
    # country = 'china'
    # def __init__(self,name,age):
    # self.name = name
    # self.age = age
    #
    # def eat(self):
    # print('%s is eating'%self.name)
    # '''
    # 要做的事根据类体代码得到字典让他里面有值,就用exec函数
    # exec(class_body,{},class_dic)
    # 查看造类的三要素
    # print(class_name)
    # print(class_bases)
    # print(class_dic)

    # type(类名,基类,类的名称空间)得的结果给一个变量名People1
    # People1 = type(class_name,class_bases,class_dic)
    # print(People1)
    # obj1 = People1('yj',25)
    # obj1.eat()


    # 第二种 自定义元类
    # 自定义的话就是把type换成自己写的类名字

    # 定义自己的元类不一定所有的功能都要自己写,大部分都是源自type的所以继承
    # class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义的类
    # def __init__(self,class_name,class_bases,class_dic):
    #控制逻辑
    # if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0:
    # raise TypeError('类中必须有文档注释,并且文档注释不能为空')
    # if not class_name.istitle():
    # raise TypeError('类名首字母必须大写')
    # print(self) #现在是 People
    # print(class_name)
    # print(class_bases)
    # print(class_dic)
    # 上面的改写的功能是把父类的覆盖掉了,父类的可能还有些其他有用的代码
    # 所以super括号括起来,自己的类名,逗号self就是People,然后括号__init__也需要把三个参数传进去
    # 这是保险起见把父类的功能也重用一下
    # super(Mymeta,self).__init__(class_name,class_bases,class_dic)


    # 分析class的运行原理:
    # 1.拿到一个字符串格式的类名 class_name
    # 2.拿到一个类的基类们 class_bases
    # 3.执行类体代码,拿到一个类的名称空间 class_dic
    # 4.调用type(class_name,class_bases,class_dic)将得到的结果赋值给个变量名People
    # People = type(class_name,class_bases,class_dic)

    # class People(object,metaclass=Mymeta): # People = Mymeta(类名,基类们,名称空间)
    #加文档注释 不写 为空都是不合法的
    # '''这是一个People类'''
    # country = 'china'
    # def __init__(self,name,age):
    # self.name = name
    # self.age = age

    # def eat(self):
    # print('%s is eating'%self.name)

    # print(People.__dict__) #看名称空间
    # 文档注释是空
    # {'__module__': '__main__', 'country': 'china', '__init__': <function People.__init__ at 0x000001E1BAFD9950>, 'eat': <function People.eat at 0x000001E1BAFD99D8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
    # 应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程





    # 3.3储备知识 __call__
    # __开头__结尾 会在满足某种条件时自动触发执行
    # class Foo:
    # def __call__(self, *args, **kwargs):
    # print('ok')
    # print(self)
    # print(args) #args就是传的位置参数
    # print(kwargs) #kwargs就是传的关键字参数
    #
    # obj = Foo()
    # # obj() #要想让obj这个对象变成一个可调用的对象,需要早该对象的类中定义一个方法__call__方法
    # # 该方法会在调用对象是自动触发
    # obj(1,2,3,x=1,y=2)



    # 自定义元类控制类的产生过程
    # 其实自定义类定义完了之后,还要去调用那个类,还想要去控制自定义类的那个调用过程
    # 也就是自定义类创造对象的过程
    # 4. 自定义元类来控制类的调用过程,即类的实例化过程

    class Mymeta(type):
    def __call__(self, *args, **kwargs):
    # print(self) #self是People
    # print(args)
    # print(kwargs)
    # 1.先造出一个People空对象
    obj = self.__new__(self)
    # 2.为该空对象初始化独有的属性
    self.__init__(obj,*args,**kwargs)
    # 3.返回一个初始化好的obj
    return obj



    class People(object,metaclass=Mymeta): # People = Mymeta(类名,基类们,名称空间)
    # 加文档注释 不写 为空都是不合法的
    '''这是一个People类'''
    country = 'china'
    def __init__(self,name,age):
    self.name = name
    self.age = age

    def eat(self):
    print('%s is eating'%self.name)

    # 分析:调用People的目的
    # 1.先造出一个People空对象
    # 2.为该空对象初始化独有的属性

    obj = People('zrg',age=24)
    print(obj.__dict__)
    print(obj.name)
    obj.eat()


    # 调对象就是调对象内的call方法,调对象拿到的返回值就是call方法的返回值
    # 不写返回值就是一个None
  • 相关阅读:
    shell脚本中echo颜色设置
    整合Spring+Hibernate+Struts2的时候发现json数据一直无法传到页面,提示no-Session
    分页查询——Hibernate Criteria实现一次查询取得总记录数和分页后结果集
    JS,JQ 格式化小数位数
    简单地做一下“回到顶部”按钮,用jQuery实现其隐藏和显示
    二级联动,三级联动,初学者,纯javascript,不含jQuery
    Oracle数据库知识要点
    ParameterizedType理解笔记
    JDBC mysql 相关内容笔记
    在做关于NIO TCP编程小案例时遇到无法监听write的问题,没想到只是我的if语句的位置放错了位置,哎,看了半天没看出来
  • 原文地址:https://www.cnblogs.com/zhangrenguo/p/10042423.html
Copyright © 2020-2023  润新知