写在最前面:
一些很重要的知识,我的写得有点乱,也可以去看这些文章,
Python 面向对象(初级篇)
来自 http://python.jobbole.com/82023/
python 面向对象(进阶篇)
来自 http://python.jobbole.com/83747/
深刻理解Python中的元类(metaclass)
来自 http://python.jobbole.com/21351/
首先来看一个例子,正常情况下我们定义并且实例一个类如下
class Foo(object):
def __init__(self):
pass
obj = Foo() # obj是通过Foo类实例化的对象
上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
print type(obj) # 输出: Foo 表示,obj 对象由Foo类创建
print type(Foo) # 输出:type表示,Foo类对象由 type 类创建
如果按照一切事物都是对象的理论:
obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
两个基本的类
这里和有必要提到一下在Python中有两个最基本的对象,
的类型是 (它本身), 的父类是 的类型是 , 没有父类
在Python对象系统中,
类的创建
主要有两种方式,不过本质上都是一样的,都是通过type类来实例一个用户类
普通方式
Python
1 class Foo(object):
2
3 def func(self):
4 print 'hello wupeiqi'
特殊方式(type类的构造函数)
Python
1 def func(self):
2 print 'hello wupeiqi'
3
4 Foo = type('Foo',(object,), {'func': func})
5 #type第一个参数:类名
6 #type第二个参数:当前类的基类
7 #type第三个参数:类的成员
由上面可以看出来 , Foo类是由type类实例而来,那么具体的创建的过程是怎么样的呢,接着往下面看:
来了解几个概念
new 和 init()和metaclass__:
- new函数是实例一个类所要调用的函数,每当我们调用obj = Foo()来实例一个类时,都是先调用new()
- 然后再调用init()函数初始化实例. init()在new()执行后执行,
- 类中还有一个属性 metaclass,其用来表示该类由 谁 来实例化创建,所以,我们可以为 metaclass 设置一个type类的派生类,从而查看 类 创建的过程。
阐述运行过程
mytype产生一个叫做Foo的实例,主要的原理就是设置了,metaclass=MyTypoe,这样就指定mytype类来实例foo类,如果Python没有找到metaclass,它会继续在(父类)中寻找 metaclass属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到metaclass,它就会在模块层次中去寻找metaclass,并尝试做同样的操作。如果还是找不到metaclass,Python就会用内置的type来创建这个类对象。
mytype类中的new方法返回了一个对象,所有的Python实例都是这句代码创建的type.new(cls,name,bases,attrs)
mytype的init()函数初始化Foo类,在这里我们可以和在new()函数一样设置Foo类的attr属性,比如类中的方法,字段属性等
和Foo类的创建过程一样,studen类继承了Foo类,所以重复123步骤,得到一个studen类
当用户使用Foo()或者studen()来实例类时,会默认调用类中的new()方法,要是之类里面没有这个方法就到父类里面寻找new(),我们可以充分利用这个new函数,比如来实现Python中的单例模式,或者对类成员进行批量的修改等等.
产生了一个实例后马上执行init()函数,进行初始化实例,
由上面的运行结果可以看出,其中Foo和studen类的类型是
,这也证明了Foo类和studen类都是由MyType实例而来…而第三个例子,可以看出Foo2类的类型是 ,这个并不例外,Foo2继承了object类,(这个,还是跳过吧,前面已经讲过type和object相爱相杀的关系了)
##总结:
首先,你知道了类其实是能够创建出类实例的对象。好吧,事实上,类本身也是实例,当然,它们是元类的实例。Python中的一切都是对象,它们要么是类的实例,要么是元类的实例,除了type。type实际上是它自己的元类,在纯Python环境中这可不是你能够做到的,这是通过在实现层面耍一些小手段做到的。其次,元类是很复杂的。对于非常简单的类,你可能不希望通过使用元类来对类做修改。你可以通过其他两种技术来修改类:
1. Monkey patching
2. class decora