博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python的metaclass、`__new()__`、单例模式
阅读量:6293 次
发布时间:2019-06-22

本文共 4482 字,大约阅读时间需要 14 分钟。

元类的引入

    在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 cprint c1print type(c1)c1.fun()c1.fun_base()print c1.a

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

<__main__.Foo object at 0x000000000270DF28>
<__main__.Foo object at 0x000000000270DF28>This is funthis is base fun1

当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 ', selfc1 = C(1, 2, a=3)print c1c2 = C(3, 4, b=4)print c2

其输出为

__new__ called. args is  (1, 2) kwargs is  {'a': 3}the type of cls is  
the cls is
the type of c is
the c is <__main__.C object at 0x00000000026ADE48>__init__ called. args is (1, 2) kwargs is {'a': 3}the type of self is
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
the cls is
the type of c is
the c is <__main__.C object at 0x00000000026ADE80>__init__ called. args is (3, 4) kwargs is {'b': 4}the type of self is
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()__也不会被调用)
  • clsself:二者分别是__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):        passs1 = Singleton()s2 = Singleton()print s1print s2print s1 == s2<__main__.Singleton object at 0x000000000278D080><__main__.Singleton object at 0x000000000278D080>True

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

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

转载于:https://www.cnblogs.com/tony-wong/p/4897130.html

你可能感兴趣的文章
磁盘空间满引起的mysql启动失败:ERROR! MySQL server PID file could not be found!
查看>>
点播转码相关常见问题及排查方式
查看>>
[arm驱动]linux设备地址映射到用户空间
查看>>
弗洛伊德算法
查看>>
【算法之美】求解两个有序数组的中位数 — leetcode 4. Median of Two Sorted Arrays
查看>>
精度 Precision
查看>>
Android——4.2 - 3G移植之路之 APN (五)
查看>>
Linux_DHCP服务搭建
查看>>
[SilverLight]DataGrid实现批量输入(like Excel)(补充)
查看>>
秋式广告杀手:广告拦截原理与杀手组织
查看>>
翻译 | 摆脱浏览器限制的JavaScript
查看>>
闲扯下午引爆乌云社区“盗窃”乌云币事件
查看>>
02@在类的头文件中尽量少引入其他头文件
查看>>
JAVA IO BIO NIO AIO
查看>>
input checkbox 复选框大小修改
查看>>
BOOT.INI文件参数
查看>>
vmstat详解
查看>>
新年第一镖
查看>>
unbtu使用笔记
查看>>
OEA 中 WPF 树型表格虚拟化设计方案
查看>>