29.Python中的元类

作者: TensorFlow开发者 | 来源:发表于2018-07-09 17:16 被阅读0次

回顾

前面在学习Python编程:获取对象信息知识时,我们已经知道了type()函数。这个type()函数既可以返回一个对象的类型,又可以创建出新的类型。type()函数在传入一个参数时,返回的是对象所属的类型。这里特别要注意的是:通常所说的类比如动物类Animal、狗类Dog、猫类Cat、汽车类Car等,都是type的实例,说白了就是:动物类Animal、狗类Dog、猫类Cat、汽车类Car等,这些类的类型都是type类型。

type()函数当传入三个参数时,可以动态创建新的class对象,也就是新类型。

一个入参:获取类型type(obj)

class type(obj)官方解释:

With one argument, return the type of an object. The return value is a type object and generally the same object as returned by object.__class__.

意思大概是说:type函数传入一个参数时,返回结果是该对象的类型。返回值是type对象,和调用该对象的__class__方法返回值一样。

三个入参:动态创建新的类实例 class type(name, bases, dict)

type()函数当传入三个参数时,可以动态创建新的class对象,也就是新类型,如:通过该函数动态创建Fox类。 class type(name, bases, dict)的官方解释如下:

With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the__name__attribute; the bases tuple itemizes the base classes and becomes the __bases__ attribute; and the dict dictionary is the namespace containing definitions for class body and is copied to a standard dictionary to become the__dict__attribute. For example, the following two statements create identical type objects。

要创建一个class对象,type()函数依次传入3个参数:
1.新class的名称;
2.所要继承的父类的集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3.新class中的方法名称与函数可通过字典键值对一一绑定。例如:此参数传入:dict(my_eat=eat)这里我们把函数eat绑定到方法名my_eat上。

通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class(即通常所说的类,这里类也是一个个的实例,类是type类型)。

看到这里,你会发现这与Java中的反射机制类似的:运行时动态创建的对象、绑定属性、方法等。

示例

我们说class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。比如,我们可以通过type()函数创建出Fox类实例,而无需通过class Fox(object)...的定义:

def my_eat(obj):
    print("吃东西")

# 用type()创建类实例
Fox = type("Fox", (object,), dict(eat=my_eat))

f = Fox()

f.eat()

运行结果:

吃东西

正常情况下,我们都用class A...来定义类,但是,type()函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。

metaclass

除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass。

metaclass,直译为元类,简单的解释就是:当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。

但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。

连接起来就是:先定义metaclass,就可以创建类,最后创建实例。

所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。

metaclass是Python面向对象里最难理解,也是最难使用的魔术代码。正常情况下,你不会碰到需要使用metaclass的情况,所以,以下内容看不懂也没关系,因为基本上你不会用到。

示例

们先看一个简单的例子,这个metaclass可以给我们自定义的MyList增加一个add方法:

定义ListMetaClass,按照默认习惯,metaclass的类名总是以Metaclass结尾,以便清楚地表示这是一个metaclass:

# 定义元类ListMetaClass。metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaClass(type):
    def __new__(cls, name, bases, attrs):
        attrs["add"] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

# 自定义MyList类
class MyList(list, metaclass=ListMetaClass):
    pass

my_list = MyList()
my_list.add(2)
my_list.add(4)
print(my_list)

运行结果:

[2, 4]

我们在定义MyList类的时候还要指示使用ListMetaClass来定制类,正是通过传入关键字参数metaclass来指定的:class MyList(list, metaclass=ListMetaClass):
当我们传入关键字参数metaclass时,魔术就生效了,它指示Python解释器在创建MyList时,要通过ListMetaclass.new()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。

__new__()方法接收到的参数依次是:

  • 当前准备创建的类的对象;
  • 类的名字;
  • 类继承的父类集合;
  • 类的方法集合。

小结

本结知识,是python中生涩的知识点,难理解还几乎用不到,只做理解即可。


更多了解,可关注公众号:人人懂编程


微信公众号:人人懂编程

相关文章

  • 29.Python中的元类

    回顾 前面在学习Python编程:获取对象信息知识时,我们已经知道了type()函数。这个type()函数既可以返...

  • 29.Python之面向对象的元类

    Python之面向对象的元类 什么是元类?类的类就是元类,元类创建对象。使用class定义的类,用来产生程序员自己...

  • ios 底层-经典面试题

    1.元类中为什么会有类对象的类方法 探索中,我们知道实例方法存储在类中,类方法存储在元类中 为了探索我们面试题现象...

  • iOS开发笔记-类和元类

    先说几个概念:实例,类,元类类的定义中有一个isa指针指向元类,元类结构体中又有个isa指针指向根元类 详情参考下...

  • Python中的元类

    学懂python的元类,只要记住两句话: 道生一,一生二,二生三,三生万物 我是谁,我从哪里来,我要到哪里去? 在...

  • python中的元类

    类我简单理解就是类型,是现实对象抽象出来的模型。它是一个模具,有创建对象的能力。但是本质上它也是对象,有对象的能力...

  • Python中的类与元类

    Python的类 在Python中类也是一个对象,可以使用type()内置函数动态创建类 函数type()实际是一...

  • type与元类

    原文 1、什么是元类 通过上文的描述,我们知道了Python中的类也是对象。元类就是用来创建这些类(对象)的,元类...

  • 类模板中的友元函数

    今天写cpp的时候,忘记了类模板中的友元怎么用了记录一下 先声明类模板,和友元函数 类模板中声明友元函数 类模板外...

  • python面向对象(二)

    元类 python中,对象是由元类创建的,类也是一种对象,也就是说元类就是‘类的类’eg、电脑中的cpu、内存等等...

网友评论

    本文标题:29.Python中的元类

    本文链接:https://www.haomeiwen.com/subject/zrltpftx.html