常见类的创建方法
1
2
3
4
5
6
7
| # classic style
class A:
pass
# new style
class A(object):
pass
|
但总有些情况我们不想或是不能使用这种定义方式。希望可以用函数的方式动态的创建一个类或是继承一个类,来实现我们的需求。
python作为一种动态语言是这次这种方式的,当然这种hack方式并不推荐在较大工程中使用,会影响代码可读性和pylint等代码检查工具。
但是如果是一些小的工具函数中,使用这个方式可以很好的衔接函数式编码风格和面向对象编码风格,并且会使代码更精炼内聚性更高。
同时通过这种方式,可以更深入的研究的python的底层机制。
动态创建类的方法
其实python中提供了一个函数可以动态创建一个类,就是type函数,此函数比较常规的使用方式是type(a)这种,用来查a的类型。但其实此函数通过传不同的参数也可以实现类的定义。
type函数实现:
1
2
3
4
5
6
7
8
9
10
11
12
| class type(object):
"""
type(object) -> the object's type
type(name, bases, dict) -> a new type
"""
def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
"""
type(object) -> the object's type
type(name, bases, dict) -> a new type
# (copied from class doc)
"""
pass
|
python中动态创建一个类如下:
1
2
3
4
5
| class A(object):
pass
class B:
pass
AB = type('AB', (A, B), {'ab': None})
|
type中的参数为:
- 第一个参数为要创建的类名
- 第二个参数为继承需要继承的父类,也可以为空
- 第三个参数类中的成员定义,也可以为空字典
type的返回值为一个type,也就是一个class(python中new style的class都是继承的type这个类型)。此种方式与我们常用的声明式定义效果相同,其实python解释器中,也是通过调用type函数来定义一个类。
注意:
- 此处有个一个需要注意的点,继承多个父类的时候,只会执行tuple中第一个父类的__init__函数,这个和python的new-style class的继承初始有关,可以参看新式类的初始化相关。
- 还有个点是type函数不支持keyword arguments形式的函数赋值,原因是type为C-level API,所以不支持。
特殊情况
上述方式适用于绝大多数情况,但有一种情况特殊–继承的父类都是老式类(classic style),不能使用上述方法。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
| class A:
pass
class B:
pass
AB = type('AB', (A, B), {'ab': None})
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-42287432155c> in <module>()
3 class B:
4 pass
----> 5 AB = type('AB', (A, B), {'ab': None})
TypeError: a new-style class can't have only classic bases
|
错误原因是type会生成一个新式类,父类中必须有一个是新式类,否则会报TypeError错误。解决办法是通过types.ClassType来生成一个老式类(classic style):
1
2
3
4
5
6
| import types
class A:
pass
class B:
pass
AB = types.ClassType('AB', (A, B), {'ab': None})
|
看下types.ClassType的实现:
1
2
3
4
| # 通过type取一个老式类的类型,来生成新的类。
class _C:
def _m(self): pass
ClassType = type(_C)
|
从下面可以看出新式类和老式类的不同。
1
2
3
4
5
6
| class A(object):
pass
class B:
pass
type(A) --> type
type(B) --> classobj
|
总结:
可以通过基础类型–type和classobj来生成新的类。
文章作者
Jayden
上次更新
2020-09-09
(83adef0)
use full config.toml
许可协议
CC BY-NC-ND 4.0