本文始发于个人公众号:TechFlow,原创不易,求个关注

今天是Python专题的第16篇文章,今天我们来聊聊Python当中的元类。

元类是Python当中的高级用法,如果你之前从来没见过这个术语或者是没听说过这个概念,这是非常正常的,因为一方面它的使用频率不高,另外一方面就是它相对不太容易理解。以至于很多Python开发者都理解得不是很深入,导致了市面上相关的资料也并不太多。我也是读了一些大牛的代码才开启了这扇新世界的大门。

一切都是对象

我们之前的时候曾经介绍过,在Python当中一切都是对象,注意,是一切都是对象。我们都知道对象是类实例化之后的结果,可以简单地将类和对象类比成模具和成品的关系。模具是类,而根据模具做出来的产品是对象。

这个比喻思想比较接近,但是不完美。因为实际当中一个模具可以做出多个产品,一个产品只有一个模具。但编程语言当中不同,由于类之间可以继承以及多继承,也就是说一个对象可以对应多个类。所以这个比喻不是特别合适,但是类和对象的关系是没错的。

但是这就有了一个问题,既然Python当中一切都是对象,那么是不是说类其实也是一个对象呢?也就是说一个模具其实也是另外一个模具的产品?同样,这个模具的模具其实也是另外一个模具的产品,那么我们一直追问下去会怎么样呢?

很简单,我们做个实验就知道了,我们可以用_class__关键字来查看一个变量的类型,那么我们反复调用就可以查看其中的关系了:

从上面的图中我们可以发现,num是int类型的变量。我们继续查看int这个类型的类型,得到了type类型。而当我们去查看type的类型的时候,会发现我们得到的还是一个type的类型。

所以我们可以明白了,type是Python中用来创建所有类的元类,是所有模具的模具。在Python当中,我们把一个类的类叫做元类(metaclass)。所以type就是Python当中内置的元类,我们也可以自己创建我们需要的元类。通过元类,我们创建的对象也是一个类,而不是一个实例。

动态创建类

理解了type是一切类基础之后,再来看动态类就简单了。动态类是动态语言最大的特性之一,作为典型的动态语言,Python自然也是支持类型的动态创建的。

在Python当中,创建动态类型的一种方式就是通过type关键字。说起来有些意想不到,type函数不是用来查询对象所属的类型的吗,怎么还可以创建类呢?

这其实是type的另外一种用法,作为元类来创建一个类。在这种用法,type函数接收3个参数,分别是类型的名称,父类的元组,以及一个字典。除了第一个参数之外,后面两个参数都可以为空。比如我们来看一个例子:

注意,type返回的结果是一个类,而不是一个实例。所以我们还可以通过它创建实例:

hello = Hello()

这样创建出来的是最简单的空类,它什么也没有,和下面的代码等价。

class Hello:
pass

我们也可以在type的参数当中为这个类填充属性和方法:

def hello_world(self):
print('hello') Hello = type('Hello', (), {'hello':hello_world, 'num': 3})

这样我们就为Hello这个类创建了一个方法叫做hello,一个属性num等于3。我们可以来调用一下试试:

也就是说我们可以使用type来根据我们的需要自行定义类,只不过type既可以获取对象的类型又可以创建新的类,看起来可能觉得有些不太直观,但是其实这也是说得通的。我们在Python当中通过调用str创建一个string对象,通过int来创建一个integer对象,那么通过type则是创建一个类的对象。

实现继承

我们之前说了,当我们使用type来创建类的时候,还可以传入父类的元组从而实现类的继承。

比如我们再创建一个叫做World的类继承刚才通过type创建出来的Hello类,然后在为它加上额外的函数:

def say_world(self):
print('World') World = type('World', (Hello, ), {'world': say_world})

注意这里传入第二个参数是父类的元组,既然是元组,那么当元素只有一个的时候,需要加上逗号,表示这是一个元组。这样创建出来的类和我们通过class定义的静态类效果是一样的:

也就是说,我们可以先把函数实现,然后再根据任务的需要把这些函数组装成新的类。显然,这和传统的C++以及Java这些静态类型的语言相比,要灵活得多。

总结

我们固然可以通过type来创建动态创建类,但是从上面的使用过程也应该看得出来,这样使用起来并不太方便,并且很多进阶的功能很难实现。举个简单的例子,比如我们想要动态地为一个已有的类添加一些动态的方法,生成新的类。我们使用type就很难实现。type也的确不是Python元类的主要运用,metaclass才是王道,但由于篇幅限制,这部分将放在下一篇文章当中。

当然,元类是一个非常高级的用法,以至于Python的创始人说99%的Python程序员并不需要用到它。所以如果你觉得理解起来非常费劲的话也没有关系,知道这么个概念就可以了。

今天的内容就是这些,如果喜欢本文,可以的话,请点个关注,给我一点鼓励,也方便获取更多文章。

Python面试常用的高级用法,怎么动态创建类?的更多相关文章

  1. 使用python type动态创建类

    使用python type动态创建类 X = type('X', (object,), dict(a=1))  # 产生一个新的类型 X 和下列方法class X(object):    a = 1效 ...

  2. Python中type()详解:动态创建类

    众所周知: type()函数可以查看变量的类型: 先看一个简单的列子来看一下type查看变量类型 class Animal(): pass a=Animal() print(type(a)) prin ...

  3. python动态创建类的声明

    动态创建类的声明 使用内置函数type,原型:class type(name, bases, dict)name是类的名字,相当于__class__bases是类的基类,元组,可以有多个基类,但是基类 ...

  4. Python 中使用动态创建类属性的机制实现接口之后的依赖

    我们在自动化测试中经常会需要关联用例处理,需要动态类属性: 推荐使用第二种方法: 创建:setattr() 获取:getattr() 两种,如何创建 类属性 loan_id # 第一种,创建 # 类名 ...

  5. python-获取类名和方法名,动态创建类和方法及属性

    获取类名和方法名1.在函数外部获取函数名称,用.__name__获取2.在函数内部获取当前函数名称,用sys._getframe().f_code.co_name方法获取3.使用inspect模块动态 ...

  6. ios动态创建类Class

    [Objective-C Runtime动态加载]---动态创建类Class 动态创建类Class,动态添加Class成员变量与成员函数,动态变量赋值与取值,动态函数调用等方法 a.使用objc_al ...

  7. OC 反射-->动态创建类

    系统方法 NSLog(@"%s", __func__); //打印出类的方法名称,如: //打印结果:2018-02-22 10:52:15.394575+0800 DemoRun ...

  8. type动态创建类

    在一些特定场合,需要动态创建类,比如创建表单,就会用到type动态创建类,举个例子: class Person(object): def __init__(self,name,age): self.n ...

  9. 动态创建类/ swizzle class

    动态创建类 Class subclass = objc_allocateClassPair(baseClass, subclassName, );//生成,指定父类 //添加方法,变量...一些操作 ...

随机推荐

  1. 一、HDFS 原理分析

    HDFS 全称 Hadoop Distribute File System,是 Hadoop 的一个分布式文件系统 一.HDFS 的系统结构 1.1 数据块 -- block 文件在 HDFS 上分块 ...

  2. spark机器学习从0到1支持向量机SVM(五)

        分类 分类旨在将项目分为不同类别. 最常见的分类类型是二元分类,其中有两类,通常分别为正数和负数. 如果有两个以上的类别,则称为多类分类. spark.mllib支持两种线性分类方法:线性支持 ...

  3. zabbix 自动发现主机并关联模板

    一.自动发现添加主机 1.利用agent自动发现主机 Configuration - Discovery -Create discovery rule 2.将自动发现的主机关联模板 Configura ...

  4. JSP知识点回顾

  5. Linux 下批量杀死进程

    ps aux|grep python|grep -v grep|cut -c 9-15|xargs kill -15 管道符“|”用来隔开两个命令,管道符左边命令的输出会作为管道符右边命令的输入.下面 ...

  6. 2.Redis安装和简单使用

    (1)安装Redis Redis目前只支持Linux系统,因为开发此软件的创始者认为,Redis是为后台数据服务的,所以认为该软件使用在纯净的服务环境下,而不是应用型操作系统下,而Linux作为服务器 ...

  7. 【QT】利用pyqt5实现简单界面

    Topic: 利用pyqt5编写简单界面Env:win10 + Pycharm2018 + Python 3.6.8Date: 2019/4/29 by hw_Chen2018            ...

  8. [Objective-C] 015_Delegate(委托代理)

    Delegate在iOS开发中随处可见,Delegate是一种功能强大的软件架构设计理念,它的功能是程序中一个对象代表另一个对象,或者一个对象与另外一个对象协同工作(如小明喜欢一个女孩如花,却苦于没有 ...

  9. HttpServletRequestWrapper 类&过滤指定文字

    HttpServletWrapper 和 HttpServletResponseWrapper 1). Servlet API 中提供了一个 HttpServletRequestWrapper 类来包 ...

  10. Python所有异常错误的父类--BaseException

    BaseException # 所有异常的基类 +-- SystemExit # 解释器请求退出 +-- KeyboardInterrupt # 用户中断执行(通常是输入^C) +-- Generat ...