一切皆为对象
在刚开始学Python面向对象时,就经常看到一句话:python中,一切皆为对象。当初对这句话的理解并不深,只能明白第一层,对象?不就是一个类的实例化么。
1 | class A: |
然而,随着对python进一步的学习探索,特别是了解了闭包、装饰器、魔术方法等后,才明白所有的数据类型也是对象,函数也是对象,方法也是对象,甚至,类也是对象!当使用class
关键字,python解释器在执行的时候就会在内存中创建一个对象,
1 | class A: |
这个对象的名字就叫A
,这个类对象A
拥有创建对象,即实例对象的能力。
那么类既然是对象,那类又是由谁创建的呢?答案就是:type。
造物主type
type()
函数是一个我们非常常用的函数,它可以帮助我们查看对象的类型,就像这样:
1 | class A: |
不过,有没有发现,再查看类对象A
时,返回的类型是type
!
再试试其它内置类:
1 | print(type(int)) # 输出:<class 'type'> |
无一例外,内置类的类型也全部都是type
。
没错,这个朴实无华,平平无奇的type
其实是一个隐藏boss、造物主,它是所有类的类,所有的类都是type
的实例对象。
动态创建类
type
除了常用的查看对象类型的用法外,还有一种完全不同的用法,就是动态创建类。
它可以这样用:
1 | type('',(),{}) |
可以接收三个参数:
- 第一个参数为类名
- 第二个参数为父类的名字(注意不是字符串)
- 第三个参数可以定义类的属性、方法(包括静态方法、类方法)
我们来试试:
1 | def func(self): |
可以看到,通过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 | class A: |
上面例子中,我们定义了一个类A
,它的实例对象a
,通过a.__class__
可以看到,它有A
实例而来,而a.__class__.__class__
即可以看到A
由谁实例而来,结果显示,它由type
实例而来。
除了自定义的类对象是由type
实例而来,我们再看看python内置的数据结构对象又是谁实例出来的:
1 | print('-------int--------') |
可以看到,每一种数据类型对象,其实也都是由元类type
实例而来,type
就是Python的内置元类,当然,我们也可以自己定义一个元类。
自定义元类
因为type
是Python的内置元类,所以我们如果想自定义一个元类,即创建一个新的类型,可以通过继承type
来实现:
1 | class A(type): |
我们定义了一个类A
,它继承于type
,那么它就是一个新的元类,它拥有了实例类对象的能力。当定义一个类B
,并通过参数metaclass
来指定它的元类为A
,此时我们再查看类B
的类型为新元类A
;查看它是由谁实例而来,也是新元类A
。
先有鸡还是先有蛋?
查看type
的源码可以看到:
1 | class type(object): |
type
居然继承于object
,不是所有的类都是由它创建的吗?
而看object
的源码:
1 | class object: |
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。
元类、类、实例关系图:
关于type
和object
关系的探讨,有两位网络上的大神我觉得分析的非常透彻和清晰,这里贴出来以供学习参考:
《Python 的 type 和 object 之间是怎么一种关系?》
元类的作用
元类的主要目的就是为了当创建类时能够自动地改变类。
比如假设一个简单的需求,在我定义一个类的时候,我希望它都能有一个默认的类属性。
用元类来实现以下:
1 | class A(type): |
因为我们希望能控制对象的创建,所以重写了__new__
,并且,由于创建的对象是类,所以需要继承元类type
。这样,只要定义的类指定了metaclass
为A
,那么所有的类对象,都会有一个默认对象attr
。
简单来说,就是我们在创建类的时候,自定义了它的行为。要达到这种效果,似乎装饰器也可以实现吧?
1 | def extended(cls): |
同样都是扩展类的功能,装饰器也一样能实现,但是它们有一个明显区别就是,装饰器不会影响对象本身,而metaclass是拦截了对象的构造,直接对对象进行了改造。
装饰器就像钢铁侠,通过外部装备来强化自己;而metaclass像美国队长,通过改变自身的基因序列让其能力超越了人类。
现在,回到本文的主题元类这两个字上来,什么叫元类(metaclass)?从字面上来讲,“元”的意思是“本源”、“根本”的意思,那么就是所有元类的祖宗的意思咯?非也非也,如果是这样,object
第一个不答应。而meta这个词,词根来自希腊语,有“超越”、“变形”的意思,所以实际上应该理解为超越类,变形类更为准确,而元类确实正如我们所说,它能让类对象拥有“超越变形”的能力。
只是,以我目前的水平,还无法真正领会到元类这强大的能力,正如Python大神Tim Peters所说:
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。”