常见类的创建方法

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中的参数为:

  1. 第一个参数为要创建的类名
  2. 第二个参数为继承需要继承的父类,也可以为空
  3. 第三个参数类中的成员定义,也可以为空字典

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来生成新的类。