您的位置:首页 > 编程语言 > Python开发

Python的metaclass、`__new()__`、单例模式

2015-10-21 10:38 381 查看

元类的引入

    在Python的世界里,一切均是对象,包括函数、class;如果class是用来生成对象的,那么作为对象的class,又是由谁生成的呢?答应就是meta-class,meta-class是用来生成class的class。在python中,有两个默认的meta class,分别是经典类的types.ClassType, 新式类的type

元类生成class的过程

type(calss_name, (parent_class,),{‘function_name’:function, 'property_name':property_value})

对于形如下面的class

class Base(object):
def fun_base(self):
print 'this is base fun'

class Foo(Base):
def __init__(self):
self.a = 1

def fun(self):
print 'this is fun'

如果使用meta-class来生成同样的class,其过程

class Base(object):
def fun_base(self):
print 'this is base fun'

def fun(self):
print 'This is fun'

c = type('Foo', (Base,), {'fun':fun, 'a':1})
c1 = c()
print c
print c1
print type(c1)
c1.fun()
c1.fun_base()
print c1.a

其输出为,type()的返回值是一个class,由其生成的对象c1 其类型是class Foo,c1可以调用其自己与其父类的成员函数,也可以访问自己的属性。其面向对象的所有属性与上面定义的class Foo一致

<class '__main__.Foo'>
<__main__.Foo object at 0x000000000270DF28>
<class '__main__.Foo'>
<__main__.Foo object at 0x000000000270DF28>
This is fun
this is base fun
1

当python的解释器遇到语句class的时候,就会寻找该class的meta clas去生成其对象,也就是class本身,其查找meta clas的过程如下:

1.class是否定义属性
__metaclass__


2.class的父类是否定义属性
__metaclass__


3.class所在的模块是否定义
__metaclass__


4.使用默认的metaclass:旧式类 types.ClassType;新式类 type

其实,在python的定义中,meta class不仅仅局限于type和type.ClassType,任何接受参数name,tuple,dict,返回值为class的可调用变量都可以当做meta class


This variable can be any callable accepting arguments for name, bases, and dict. Upon class creation, the callable is used instead of the built-in type().


那么借助这个定义,我们可以对type()做一定的封装,让称为meta class

我们可以定义自己的meta class

class MetaCls(type):
def __new__(cls, name, bases, dict):
# do customizing here
return super(MetaCls, cls).__new__(cls, name, bases, dict)

我们甚至可以把一个函数变成一个meta class

def metacls_func(name, bases, dict):
# do customizing here
return type(name, bases, dict)

__new()__
__init()__

在python中,
__new()__
__init()__
是与对象生成密切相关的两个magic method,前者完成对象生成过程,后者完成对象的初始化过程。

class C(object):
def __new__(cls, *args, **kwargs):
# cls is a class, and __new__() returns a object
print '__new__ called. args is ', args, 'kwargs is ', kwargs
print 'the type of cls is ', type(cls), ' the cls is ', cls
c = super(C, cls).__new__(cls, *args, **kwargs)
print 'the type of c is ', type(c), ' the c is ', c
return c

def __init__(self, *args, **kwargs):
print '__init__ called. args is ', args, 'kwargs is ', kwargs
print 'the type of self is ', type(self), 'the self is ', self

c1 = C(1, 2, a=3)
print c1
c2 = C(3, 4, b=4)
print c2

其输出为

__new__ called. args is  (1, 2) kwargs is  {'a': 3}
the type of cls is  <type 'type'>  the cls is  <class '__main__.C'>
the type of c is  <class '__main__.C'>  the c is  <__main__.C object at 0x00000000026ADE48>
__init__ called. args is  (1, 2) kwargs is  {'a': 3}
the type of self is  <class '__main__.C'> the self is  <__main__.C object at 0x00000000026ADE48>
<__main__.C object at 0x00000000026ADE48>
__new__ called. args is  (3, 4) kwargs is  {'b': 4}
the type of cls is  <type 'type'>  the cls is  <class '__main__.C'>
the type of c is  <class '__main__.C'>  the c is  <__main__.C object at 0x00000000026ADE80>
__init__ called. args is  (3, 4) kwargs is  {'b': 4}
the type of self is  <class '__main__.C'> the self is  <__main__.C object at 0x00000000026ADE80>
<__main__.C object at 0x00000000026ADE80>

这段代码说明:

__new()__
的作用:当调用
c1 = C(1, 2, a=3)
时,
class
语句会查找
__metaclass__
生成
class C
,之后
__new()__
被调用,通过调用父类的
__new()__
生成对象(
super(C, cls).__new__(cls, *args, **kwargs)
的返回值是一个Class C的一个对象,类型是class C)

__init()__
的作用:当
__new()__
返回一个对象之后,会继续调用
__init()__
进行对象的初始化过程。(如果
__new()__
没有返回一个对象,那么后续的
__init()__
也不会被调用)

cls
self
:二者分别是
__new()__
__init()__
的参数,从上面的代码可以看出,
cls
就是由
metaclass type
生成的
class C
,而
self
就是
class C
生成的对象,在两次调用中,这个对象分别就是
c1 = C(1, 2, a=3) c2 = C(3, 4, b=4)
生成的c1和c2(
self
和它们的地址是一致的)

__new()__
__init()__
的参数传递: 当调用对象生成语句
c1 = C(1, 2, a=3)
的时候,会携带不定参数
(1, 2, a=3)
,这些参数会分别被传递给
__new()__
__init()__


python的单例

可以使用metaclass与
__new()__
的特性,构建python的单例模式

class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance

def __init__(self, *args, **kwargs):
pass

s1 = Singleton()
s2 = Singleton()
print s1
print s2
print s1 == s2

<__main__.Singleton object at 0x000000000278D080>
<__main__.Singleton object at 0x000000000278D080>
True

通过增加类属性_instance记录单例对象,每次生成对象的时候,如果对象已经生成过,那么就会将第一次生成对象返回,否则才会生成一个对象,从而实现单例模式。从代码的输出也可以看到,多次生成对象,生成的对象总是同一个

那么meta-class是不是对象呢?(待补充)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: