二、使用 type()
动态创建类
因为类也是对象,所以我们可以在程序运行的时候创建类。Python 是动态语言。动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。在之前,我们先了了解下 type()
函数。
首先我们新建一个 hello.py
的模块,然后定义一个 Hello 的 class ,
class Hello(object):
def hello(self, name='Py'):
print('Hello,', name)
然后在另一个模块中引用 hello 模块,并输出相应的信息。其中 type()
函数的作用是可以查看一个类型和变量的类型。
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
from com.twowater.hello import Hello
h = Hello()
h.hello()
print(type(Hello))
print(type(h))
输出的结果是怎样的呢?
Hello, Py
<class 'type'>
<class 'com.twowater.hello.Hello'>
上面也提到过,type()
函数可以查看一个类型或变量的类型,Hello
是一个 class
,它的类型就是 type
,而 h
是一个实例,它的类型就是 com.twowater.hello.Hello
。前面的 com.twowater
是我的包名,hello
模块在该包名下。
在这里还要细想一下,上面的例子中,我们使用 type()
函数查看一个类型或者变量的类型。其中查看了一个 Hello
class 的类型,打印的结果是: <class 'type'>
。其实 type()
函数不仅可以返回一个对象的类型,也可以创建出新的类型。class 的定义是运行时动态创建的,而创建 class 的方法就是使用 type()
函数。比如我们可以通过 type()
函数创建出上面例子中的 Hello
类,具体看下面的代码:
# -*- coding: UTF-8 -*-
def printHello(self, name='Py'):
# 定义一个打印 Hello 的函数
print('Hello,', name)
# 创建一个 Hello 类
Hello = type('Hello', (object,), dict(hello=printHello))
# 实例化 Hello 类
h = Hello()
# 调用 Hello 类的方法
h.hello()
# 查看 Hello class 的类型
print(type(Hello))
# 查看实例 h 的类型
print(type(h))
输出的结果如下:
Hello, Py
<class 'type'>
<class '__main__.Hello'>
在这里,需先了解下通过 type()
函数创建 class 对象的参数说明:
1、class 的名称,比如例子中的起名为 Hello
2、继承的父类集合,注意 Python 支持多重继承,如果只有一个父类,tuple 要使用单元素写法;例子中继承 object 类,因为是单元素的 tuple ,所以写成 (object,)
3、class 的方法名称与函数绑定;例子中将函数 printHello
绑定在方法名 hello
中
具体的模式如下:
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
好了,了解完具体的参数使用之外,我们看看输出的结果,可以看到,通过 type()
函数创建的类和直接写 class 是完全一样的,因为Python 解释器遇到 class 定义时,仅仅是扫描一下 class 定义的语法,然后调用 type()
函数创建出 class 的 。
不过一般的情况下,我们都是使用 class ***...
的方法来定义类的,不过 type()
函数也可以让我们创建出类来。也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。
可以看到,在 Python 中,类也是对象,你可以动态的创建类。其实这也就是当你使用关键字 class 时 Python 在幕后做的事情,而这就是通过元类来实现的。