一切皆为对象

在刚开始学Python面向对象时,就经常看到一句话:python中,一切皆为对象。当初对这句话的理解并不深,只能明白第一层,对象?不就是一个类的实例化么。

1
2
3
4
5
6
7
class A:
pass

a = A()
print(a)
# 输出
<__main__.A object at 0x0000023DF09976D8>

然而,随着对python进一步的学习探索,特别是了解了闭包、装饰器、魔术方法等后,才明白所有的数据类型也是对象,函数也是对象,方法也是对象,甚至,类也是对象!当使用class关键字,python解释器在执行的时候就会在内存中创建一个对象,

1
2
3
4
5
class A:
pass
print(A)
# 输出:
<class '__main__.A'>

这个对象的名字就叫A,这个类对象A拥有创建对象,即实例对象的能力。

那么类既然是对象,那类又是由谁创建的呢?答案就是:type

造物主type

type()函数是一个我们非常常用的函数,它可以帮助我们查看对象的类型,就像这样:

1
2
3
4
5
6
7
8
9
class A:
pass

print(type(1)) # 输出:<class 'int'>
print(type('123')) # 输出:<class 'str'>
print(type([1, 2, 3])) # 输出:<class 'list'>
print(type({"a": 1})) # 输出:<class 'dict'>
print(type((1,))) # 输出:<class 'tuple'>
print(type(A)) # 输出:<class 'type'>

不过,有没有发现,再查看类对象A时,返回的类型是type

再试试其它内置类:

1
2
3
4
5
print(type(int)) # 输出:<class 'type'>
print(type(str)) # 输出:<class 'type'>
print(type(list)) # 输出:<class 'type'>
print(type(dict)) # 输出:<class 'type'>
print(type(tuple)) # 输出:<class 'type'>

无一例外,内置类的类型也全部都是type

没错,这个朴实无华,平平无奇的type其实是一个隐藏boss、造物主,它是所有类的类,所有的类都是type的实例对象。

动态创建类

type除了常用的查看对象类型的用法外,还有一种完全不同的用法,就是动态创建类。

它可以这样用:

1
type('',(),{})

可以接收三个参数:

  • 第一个参数为类名
  • 第二个参数为父类的名字(注意不是字符串)
  • 第三个参数可以定义类的属性、方法(包括静态方法、类方法)

我们来试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def func(self):
return self.name

@staticmethod
def static_func():
return 'this is a static method'

def cls_func(cls):
return cls.name

class AFarther:
a_father_name = 'java'

A = type('A', (AFarther,), {'name': 'python', 'func': func, 'static_func': static_func, 'cls_func': cls_func})

print(A.__dict__)
print(A().func())
print(A().static_func())
print(A().cls_func())
print(A().a_father_name)
# 输出
{'name': 'python', 'func': <function func at 0x000001E7DD57C1E0>, 'static_func': <staticmethod object at 0x000001E7DD962C18>, 'cls_func': <function cls_func at 0x000001E7DD723D90>, '__module__': '__main__', '__doc__': None}
python
this is a static method
python
java

可以看到,通过type('A', (AFarther,), {'name': 'python', 'func': func, 'static_func': static_func, 'cls_func': cls_func}),实现了动态创建类,这个类的名字定义为A,它继承于类AFather,它的类属性为name="python",它的实例方法为func,静态方法为static_func,类方法为cls_func

而这,其实就是当我们用关键字class定义类时,python在幕后帮我们做的事情,通过元类来实现类的创建。

元类

元类就是用来创建类的“造物主”,简单说就是类的类,而上面我们提到的type就是一个元类,python中所有的类都不过是type的实例对象而已,我们可以通过查看对象的__class__属性来溯源它是由谁实例而来:

1
2
3
4
5
6
class A:
pass

a = A()
print(a.__class__) # 输出: <class '__main__.A'>
print(a.__class__.__class__) # 输出: <class 'type'>

上面例子中,我们定义了一个类A,它的实例对象a,通过a.__class__可以看到,它有A实例而来,而a.__class__.__class__即可以看到A由谁实例而来,结果显示,它由type实例而来。

除了自定义的类对象是由type实例而来,我们再看看python内置的数据结构对象又是谁实例出来的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
print('-------int--------')
a = 1
print(a.__class__)
print(a.__class__.__class__)

print('-------str--------')
b = '1'
print(b.__class__)
print(b.__class__.__class__)

print('-------list--------')
c = [1, 2, 3]
print(c.__class__)
print(c.__class__.__class__)

print('-------dict--------')
d = {"a": 1}
print(d.__class__)
print(d.__class__.__class__)

print('-------tuple--------')
e = (1, 2, 3)
print(e.__class__)
print(e.__class__.__class__)

# 输出:
-------int--------
<class 'int'>
<class 'type'>
-------str--------
<class 'str'>
<class 'type'>
-------list--------
<class 'list'>
<class 'type'>
-------dict--------
<class 'dict'>
<class 'type'>
-------tuple--------
<class 'tuple'>
<class 'type'>

可以看到,每一种数据类型对象,其实也都是由元类type实例而来,type就是Python的内置元类,当然,我们也可以自己定义一个元类。

自定义元类

因为type是Python的内置元类,所以我们如果想自定义一个元类,即创建一个新的类型,可以通过继承type来实现:

1
2
3
4
5
6
7
8
9
10
11
12
class A(type):
pass

class B(metaclass=A):
pass

b = B()
print(type(B))
print(b.__class__.__class__)
# 输出:
<class '__main__.A'>
<class '__main__.A'>

我们定义了一个类A,它继承于type,那么它就是一个新的元类,它拥有了实例类对象的能力。当定义一个类B,并通过参数metaclass来指定它的元类为A,此时我们再查看类B的类型为新元类A;查看它是由谁实例而来,也是新元类A

先有鸡还是先有蛋?

查看type的源码可以看到:

1
2
3
4
5
6
7
class type(object):
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
"""
...

type居然继承于object,不是所有的类都是由它创建的吗?

而看object的源码:

1
2
class object:
""" The most base type """

object又是所有类的顶点、祖宗,所有的类都继承于它。

那么问题来了,到底是先有type还是先有object?这个问题就像是先有鸡还是先有蛋一样,我没有办法回答,我只能说,它们是在面向对象的体系中,两种不同的关系的顶点:

  • 父子关系:这种关系存在于某个类(subclass)是另一个类(superclass)的特别版本之中。通常描述为“子类是一种父类”。比如:蛇是一种爬行动物(Snake is a kind of reptile)。其中,蛇(snake)是子类,爬行动物(reptile)是父类。蛇拥有爬行动物的特征,同时,又拥有标志自己是一条蛇的特征。
  • 类型实例关系:这种关系存在于两个对象之中,其中一个对象(实例)是另一个对象(类型)的具体实现。我有一条宠物蛇叫Squasher,那么Squasher就是蛇的一个实例。英文描述为:”Squasher is an instance of snake”。

object则是父子关系的顶点,所有的类,都继承于它。

type则是类型实例关系的顶点,所有的对象,都是由它是来出来的。

一句话:object是一个type的实例,type继承自object

元类、类、实例关系图:

关于typeobject关系的探讨,有两位网络上的大神我觉得分析的非常透彻和清晰,这里贴出来以供学习参考:

《python中的type和object详解》

《Python 的 type 和 object 之间是怎么一种关系?》

元类的作用

元类的主要目的就是为了当创建类时能够自动地改变类。

比如假设一个简单的需求,在我定义一个类的时候,我希望它都能有一个默认的类属性。

用元类来实现以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A(type):
def __new__(cls, class_name, parents_class, class_attr):
cls.attr = '我是默认属性'
class_attr = {'attr': cls.attr}
return type(class_name, parents_class, class_attr)


class B(metaclass=A):
pass


class C(metaclass=A):
pass


print(hasattr(B, 'attr')) # 输出:True
print(hasattr(C, 'attr')) # 输出:True

因为我们希望能控制对象的创建,所以重写了__new__,并且,由于创建的对象是类,所以需要继承元类type。这样,只要定义的类指定了metaclassA,那么所有的类对象,都会有一个默认对象attr

简单来说,就是我们在创建类的时候,自定义了它的行为。要达到这种效果,似乎装饰器也可以实现吧?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def extended(cls):
cls.attr = '我是默认属性'
return cls


@extended
class A:
pass


@extended
class B:
pass

print(hasattr(A, 'attr'))
print(hasattr(B, 'attr'))

同样都是扩展类的功能,装饰器也一样能实现,但是它们有一个明显区别就是,装饰器不会影响对象本身,而metaclass是拦截了对象的构造,直接对对象进行了改造。

装饰器就像钢铁侠,通过外部装备来强化自己;而metaclass像美国队长,通过改变自身的基因序列让其能力超越了人类。

现在,回到本文的主题元类这两个字上来,什么叫元类metaclass)?从字面上来讲,“元”的意思是“本源”、“根本”的意思,那么就是所有元类的祖宗的意思咯?非也非也,如果是这样,object第一个不答应。而meta这个词,词根来自希腊语,有“超越”、“变形”的意思,所以实际上应该理解为超越类,变形类更为准确,而元类确实正如我们所说,它能让类对象拥有“超越变形”的能力。

只是,以我目前的水平,还无法真正领会到元类这强大的能力,正如Python大神Tim Peters所说:

“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。”