元类补充

什么是元类 ?

基于python的宗旨:一切皆对象。而对象都是由类实例化得到的

class OldboyTeacher(object):
    school = ‘oldboy‘
    def __init__(self,name):
        self.name = name
    def run(self):
        print(‘%s is running‘%self.name)
t1 = OldboyTeacher(‘jason‘)
# 对象t1是由类OldboyTeacher实例化得到

那么类也是对象,它又是谁实例化得到的呢?

# 分别查看对象t1和OldboyTeacher的类型
print(type(t1))
print(type(OldboyTeacher))

# 结果为:
<class ‘__main__.OldboyTeacher‘>
<class ‘type‘>

结论1:元类就是产生类的类,默认情况下type就是所有类的元类

不依赖class关键字创建类

根据第一个结论我们能理出两条对应关系

  1.调用元类得到自定义的类

  2.调用自定义的类得到自定义的类的对象

现在我们来看第一对关系,调用元类来得到自定义的类,都需要哪些参数(OldboyTeacher=type(...),括号内传什么?)

我们自定义一个类的时候都有哪些关键的组成部分:

  1.类名

  2.类的父类

  3.类的名称空间

就以第一阶段的OldboyTeacher类为例,calss关键字创建自定义类的步骤

"""
1.获取类名(OldboyTeacher)

2.获取类的父类(object,)

3.执行类体代码获取产生的名称空间(如何获取???)

4.调用元类得到自定义类OldboyTeacher = type(class_name,class_bases,{...})
"""

补充 exec

exec : 用于执行字符串形式的python代码 只要符合python都能执行 ,并且可以指定将执行产生的名字放入某个名称空间

eval :  用于执行简单的表达式,不能有任何的特殊语法

如何执行一段字符串内部的代码并将产生的名称空间交给对应的参数?  >>>   exec()

class_body = """
school = ‘oldboy‘
def __init__(self,name):
      self.name = name
def run(self):
      print(‘%s is running‘%self.name)
"""
class_dic = {}
class_global = {}

exec(class_body,class_global,class_dic)
# class_global一般情况下都为空,除非在字符串代码内部用global关键字声明,才会将产生的名字丢到class_global全局名称空间中
print(class_dic)

{‘school‘: ‘oldboy‘, ‘__init__‘: <function __init__ at 0x000000B5D2771EA0>, ‘run‘: <function run at 0x000000B5DB5B7400>}

有了这个exec方法后,我们就可以不依赖于calss关键字创建自定义类

# 类名
class_name = ‘OldgirlTeacher‘
# 类的父类
class_bases = (object,)  # 注意必须是元祖,逗号不能忘
# 名称空间
class_body = """
school = ‘oldgirl‘

def __init__(self,name):
    self.name = name

def run(self):
    print(self.name)
"""
class_dic = {}
exec(class_body,{},class_dic)

#调用元类创建自定义类
OldgirlTeacher = type(class_name,class_bases,class_dic)
print(OldgirlTeacher)

# 结果为:<class ‘__main__.OldgirlTeacher‘>

# 并且它可以访问自身的属性和方法,并实例化产生对象
print(OldgirlTeacher.school)
print(OldgirlTeacher.run)

# 结果为:
"""
oldgirl
<function run at 0x000000229B157378>
"""

obj = OldgirlTeacher(‘jason‘)
print(obj.school)
obj.run()

"""
oldgirl
jason
"""

自定义元类控制类创建的过程

1.如何自定义元类

class Mymeta(type):  # 必须是继承了type的类才是自定义元类
    pass

class oldboyTeacher(metaclass=Mymeta):  # 通过metaclass可以指定类的元类
    school = ‘oldboy‘

    def __init__(self,name):
        self.name = name

    def run(self):
        print(‘%s is running‘%self.name)

2.__call__

思考: 一个类的对象加括号调用会执行该对象父类中的__call__方法,那么类也是对象,它在加括号实例化对象的时候,是不是也应该走它父类的__call_方法?

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)

class OldboyTeacher(object,metaclass=Mymeta):
    school = ‘oldboy‘
    def __init__(self,name):
        self.name = name
    def run(self):
        print(‘%s is running‘%self.name)
obj = OldboyTeacher(‘jason‘)

"""
打印结果:
<class ‘__main__.OldboyTeacher‘>
(‘jason‘,)
{}
"""

思考: 类加括号实例化对象的时候,有哪几个步骤?

  1.创建一个该类的空对象

  2.实例化该空对象

  3.将实例化完成的空对象返回给调用者

# 也就是说__call__里面需要做三件事
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        # 1.产生空对象
        # 2.初始化对象
        # 3.返回该对象
        # 那我先做最后一件事,返回一个123,发现
        return 123

obj = OldboyTeacher(‘jason‘)
print(obj)
# 结果就是123  

那接下来就需要我手动去干这三件事了 

class Mymeta(type):  
  def __call__(self, *args, **kwargs):
        # 1.产生一个空对象
        obj = self.__new__(self)
        # 2.实例化该对象
        self.__init__(obj,*args,**kwargs)
        # 3.返回该对象
        return obj
# 关于这个__new__,我们是不是不知道是个啥,我这里直接告诉你,它就是用来创建空对象的

思考 : 这是类加括号产生对象的过程,那么我元类加括号产生类的过程是不是也应该是这个三步

  1.产生一个空对象(指类)

  2.实例化该空对象(实例化类)

  3.将实例化完成的类对象返回

那依据上面的推导,self.__new__就是关键了,我可以在我的自定义元类里面定义一个__new__方法,看看它到底是个啥

class Mymeta(type):
    def __new__(cls, *args, **kwargs):
        print(cls)
        print(args)
        print(kwargs)

class OldboyTeacher(object,metaclass=Mymeta):
    school = ‘oldboy‘

    def __init__(self, name):
        self.name = name

    def run(self):
        print(‘%s is running‘ % self.name)

"""
<class ‘__main__.Mymeta‘>
(‘OldboyTeacher‘, (object,), {‘__module__‘: ‘__main__‘, ‘__qualname__‘: ‘OldboyTeacher‘, ‘school‘: ‘oldboy‘, ‘__init__‘: <function OldboyTeacher.__init__ at 0x000000323CEB9510>, ‘run‘: <function OldboyTeacher.run at 0x000000323CEE7158>})
{}
"""

我们发现__new__里面的*args参数接收到了三个位置参数,并且很容易辨认它们对应的就是类名,类的父类,类体代码执行后的名称空间

那么我们可不可以将__new__()的形参换一种写法

class Mymeta(type):
    def __new__(cls, class_name,class_bases,class_dic):
        print(class_name)
        print(class_bases)
        print(class_dic)
     # 这里需要记住的是,必须在最后调用元类type中的__new__方法来产生该空对象
        return type.__new__(cls,class_name,class_bases,class_dic)

class OldboyTeacher(metaclass=Mymeta):
    school = ‘oldboy‘
    def __init__(self,name):
        self.name = name
    def run(self):
        print(‘%s is running‘%self.name)

验证:

class Mymeta(type):
    def __new__(cls, class_name,class_bases,class_dic):
        print(class_name)
        print(class_bases)
        print(class_dic)
        class_dic[‘xxx‘] = ‘123‘
        if ‘school‘ in class_dic:
            class_dic[‘school‘] = ‘DSB‘
        return type.__new__(cls,class_name,class_bases,class_dic)

class OldboyTeacher(metaclass=Mymeta):
    school = ‘oldboy‘
    def __init__(self,name):
        self.name = name
    def run(self):
        print(‘%s is running‘%self.name)

print(OldboyTeacher.xxx)  # 发现可以打印出来    123
print(OldboyTeacher.school) # DSB

结论:

由此我们就可以通过自定义元类,并重写__new__方法来拦截类的创建过程,在类被创建出来之前进行一系列其他操作

原文地址:https://www.cnblogs.com/HZLS/p/11079209.html

时间: 2024-10-16 04:12:38

元类补充的相关文章

面向对象高级C(元类补充及单例模式(待补充))

有些地方还有一点模棱两可,先放在这,周六抽一个上午把这个整理完 元类中 _init_: 控制类的产生,在__new__之后 _call_: 控制对象的产生 _new_: 控制类产生最根上,其实本质最根上也不是它,是type的__call_,但是我们看不到了 object.__new__(Person) #生成Person类的对象 空的 type.__new__(cls, name, bases, dic) #生成cls这个类对象,里面有东西 #模板:控制对象的产生 class Mymeta(ty

python3全栈开发-内置函数补充,反射,元类,__str__,__del__,exec,type,__call__方法

一.内置函数补充 1.isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) #结果为True 2.issubclass(sub, super)检查sub类是否是 super 类的派生类 class Foo(object): pass class Bar(Foo): pass print(issubclass(Bar, Foo)) #结果为True

python全栈开发基础【补充】metaclass(元类)

一.创建类的执行流程 二.元类的认识 什么是元类呢?在Python3中继承type的就是元类 二.元类的示例 # 方式一 class MyType(type): '''继承type的就是元类''' def __init__(self,*args,**kwargs): print("MyType创建的对象",self) #Foo super(MyType,self).__init__(*args,**kwargs) def __call__(self, *args, **kwargs):

Python全栈开发之9、面向对象、元类以及单例

前面一系列博文讲解的都是面向过程的编程,如今是时候来一波面向对象的讲解了 一.简介 面向对象编程是一种编程方式,使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用.类就是一个模板,模板里可以包含多个方法(函数),方法里实现各种各样的功能,,对象则是根据模板创建的实例,通过实例,对象可以执行类中的方法,每个对象都拥有相同的方法,但各自的数据可能不同. 二.类.对象和方法 在Python中,定义类是通过class关键字,class后面紧接着是类名,类名通常

Python基础- 类和对象(使用、继承、派生、组合、接口、多态、封装、property、staticmethod、classmethod、反射、slots、上下文管理协议、元类)

标签: python对象 2017-07-01 16:28 79人阅读 评论(0) 收藏 举报  分类: python(11)  版权声明:本文为广大朋友交流学习,如有纰漏望不吝赐教,若存在版权侵犯请及时与我联系 目录(?)[+] 一.初识类和对象 在python3中类型就是类 先定义类在产生相对应的对象,也就是现有了概念再有了实体 class Garen: camp = 'Demacia' def attack(self): print('attack') 1.如何使用类 在python3:

Delphi 类引用 Class Reference 元类 MetaClass 用法

delphi中类引用的使用实例 类引用类引用(Class Reference)是一种数据类型,有时又称为元类(MetaClass),是类的类型的引用.类引用的定义形式如下: class of type 例如: type SomeClass = class of TObject; var AnyObj: SomeClass; TObject = class end; TClass = class of TObject; 下面的例子说明了类引用的用法: program Project1; {$APP

84、flask之信号和mateclass元类

本篇导航: flask实例化参数 信号 metaclass元类解析 一.flask实例化参数 instance_path和instance_relative_config是配合来用的:这两个参数是用来找配置文件的,当用app.config.from_pyfile('settings.py')这种方式导入配置文件的时候会用到 from flask import Flask,request app = Flask(__name__,instance_path=None, instance_relat

反射与元类

1.isinstance与issubclass 在介绍反射之前,先来介绍两个关于类的内置方法,第一个是用来判断对象是否是某一类的对象(以前常说的判断是否是某一类型,类与类型其实是一个概念),第二个则是用来判断某一类是否是继承了另一个类 l=list([1,2,3]) print(isinstance(l,list)) #True class People: def __init__(self): pass class Chinese(People): def __init__(self): pa

16 元类

面向对象学习目录 1 面向对象介绍 2 类.实例.属性.方法详解 3 面向过程与面向对象进一步比较 4 类与对象 5 属性查找与绑定方法 6 小结 7 继承与派生 8 组合 9 抽象类 10 多态 11 封装 12 绑定方法与非绑定方法 13 内置方法(上) 14 内置方法(中)之描述符 15 内置方法(下) 16 元类 一 知识储备 exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定,默认为globals() 参数三:局部作用域(字典形式),如果不指定,默