Python中的类,构造方法,元类

2018-01-15 14:28:00来源:http://timd.cn/python-class/作者:蒂米的博客人点击

分享
摘要

如无特殊说明,Python的版本都是2.X。


Python中的类

Python中有两种类:经典类 和 新式类。


新式类直接或间接继承自object类,也就是说新式类都是object类的子类;其他的类都是经典类。


# coding: utf8
import types
class Classic:
pass
class NewStyle(object):
def __new__(cls, *a, **kw):
instance = super(NewStyle, cls).__new__(cls, *a, **kw)
return instance
def __init__(self, *a, **kw):
pass
if __name__ == "__main__":
# 经典类是ClassType类型的
print isinstance(Classic, types.ClassType) # True
# 新式类是TypeType类型的
print isinstance(NewStyle, types.TypeType) # True
# 经典类 和 新式类的 mro 顺序也是不一样的
# 经典类的实例是InstanceType类型的,新式类的实例不是
print type(Classic()) == types.InstanceType # True
print type(NewStyle()) == types.InstanceType # False
新式类的构造方法

新式类有2个与对象构造相关的魔术方法:


__init__(self, ...)
__new__(cls, ...)


大多数人会以为__init__
方法是构造方法,其实不然。__init__
方法其实可以叫做初始化方法
,它的作用是在对象被创建!!!之后!!!,对对象的属性进行初始化。新式类的真正的构造方法是__new__
方法,__new__
方法是一个静态方法,哪怕在定义它的时候,并没有使用@staticmethod
装饰器。


[root@iZj6chejzrsqpclb7miryaZ ~]# cat test.py
# coding: utf8
class NewStyle(object): # 注意:一定要是新式类
def __new__(cls, *a, **kw):
print 'instance will be created...'
# 调用父类的 构造方法
instance = super(NewStyle, cls).__new__(cls, *a, **kw)
print 'instance is created...'
return instance
def __init__(self, *a, **kw):
print '__init__ is invoked...'
if __name__ == "__main__":
print NewStyle()
[root@iZj6chejzrsqpclb7miryaZ ~]# python test.py
instance will be created...
instance is created...
__init__ is invoked...
<__main__.NewStyle object at 0x7f0e1b255690>


如果本类中,没有定义__new__
构造方法,那么会去父类中找;...,一直到object类。



通常情况下,很少使用__new__
方法。在使用元类的时候,会用到__new__
方法。


元类


在Python中一切皆对象。类的实例是对象,类本身也是对象
。类是用来创建对象的,而元类是用来创建类的


下面看一下,我们怎么在Python创建类:


[root@iZj6chejzrsqpclb7miryaZ ~]# cat test.py
class MyClass1(object):
@staticmethod
def sm():
print "sm() in MyClass1"
print MyClass1
MyClass1.sm()
def sm():
print "sm() in MyClass2"
MyClass2 = type("MyClass2", (object,), {"sm": staticmethod(sm)})
print MyClass2
MyClass2.sm()
[root@iZj6chejzrsqpclb7miryaZ ~]# python test.py
<class '__main__.MyClass1'>
sm() in MyClass1
<class '__main__.MyClass2'>
sm() in MyClass2


我们可以看到,第一种是定义类的标准语法,使用class
关键字;第二种使用了type
这个类(!!!type
不是内建方法,是一个类,而且是所有新式类的最终的元类,也就是说所有的新式类,都是type的实例,都是通过type创建的!!!)。


下面看一个例子:


# coding: utf8
class NewStyle(object):
pass
# 新式类的__class__属性,指向其元类
print NewStyle.__class__ == type # True
# 新式类的对象的__class__属性,指向创建它的类
print NewStyle().__class__ == NewStyle # True

下面,看一个使用元类的例子:


[root@iZj6chejzrsqpclb7miryaZ ~]# cat test.py
# coding: utf8
import types
def log_deco(f):
def _inner(*a, **kw):
print "enter"
try:
return f(*a, **kw)
finally:
print "exit"
return _inner
class MetaClass1(type): # 注意:继承type类,而不是object类
def __new__(cls, name, bases, attrs):
# 我们可以在这里做一些hack。比如给类中所有的方法
# + 都加上一个打印日志的装饰器
for attr_name, attr in attrs.iteritems():
if isinstance(attr, types.FunctionType):
attrs[attr_name] = log_deco(attr)
# 调用父类的__new__方法,最终会调用到type.__new__方法
clazz = super(MetaClass1, cls).__new__(cls, name, bases, attrs)
print "class is created at: %r" % clazz
return clazz
class MyClass1(object):
# 通过__metaclass__类属性,为类指定元类
__metaclass__ = MetaClass1
def method(self):
print "I am method() in MyClass1"
# 类是元类的对象~
print isinstance(MyClass1, MetaClass1) # True
# 类的实例是类的对象
print isinstance(MyClass1(), MyClass1) # True
print "==="
MyClass1().method()
print "==="
[root@iZj6chejzrsqpclb7miryaZ ~]# python test.py
class is created at:
<class __main__="" myclass1="">

True
True
===
enter
I am method() in MyClass1
exit
===
</class>


在新式类中,如果类本身没通过__metaclass__
指定元类,那么则去父类找;...,一直到object,object的元类是type。


微信扫一扫

第七城市微信公众平台