
在看《Expert Python Programming》看到Meta-programming这章,一下子玩high了,为了度过漫长的节后综合症恢复期,这里记录一下玩乐的过程。
new方法是一个‘元构建器’(meta-constructor),每当一个对象被实例化时都会调用之。
class MyClass(object): def __new__(cls): print('{0}.__new__()'.format(cls.__name__)) obj = object.__new__(cls) return obj def __init__(self): print('{0}.__init__()'.format(self.__class__)) In [7]: mclass = MyClass() MyClass.__new__() <class '__main__.MyClass'>.__init__() 继承自该类的子类自然也有相应的表现:
class SubClass(MyClass): pass In [9]: sclass = SubClass() SubClass.__new__() <class '__main__.SubClass'>.__init__() 这里可以看到new是比init更早调用的,也就是说new比init更加底层,甚至在对象还没有创建的时候就可以工作,这对于需要隐式地初始化对象状态是很好的解决方案。
在Python中定义一个方法可以是这样:
def MyFunc(): print('calling Myfunc') In [12]: MyFunc() calling Myfunc 也可以是这样
def gen_MyFunc(): print('defining Myfunc') def inner_func(): print('calling Myfunc') return inner_func In [16]: MyFunc = gen_MyFunc() defining Myfunc In [17]: MyFunc() calling Myfunc 在Python中,类是一种type,type本身也是一个特殊的类,而类本身就是对象。
In [46]: MyClass.__class__ Out[46]: type In [44]: "a".__class__ Out[44]: str In [45]: "a".__class__.__class__ Out[45]: type In [37]: type.__bases__ Out[37]: (object,) In [42]: isinstance(type,object) Out[42]: True 所以我们可以这么定义一个类:
MyClass = type('MyClass',(object,),{'__init__':lambda self:None'}) 等价于
class MyClass(object): def __init__(self): pass 闭包是一组函数和存储上下文的组合。这个上下文(context)是这个函数被定义时的所处作用域中包含的引用集合。在Python中,这个环境被存储在一个cell的tuple中。你能够通过funcclosure或Python 3中的closure_属性访问它。这里就不详细展开了。
def func_closure(): inner_var = 'inner var' def inner_func(): print('accessing '+inner_var) return inner_func In [71]: func_closure()() accessing inner var 接下来我们要在上面这些功能的基础上,实现一个类似 ‘计划生育’ 的功能。借助这个功能,我们可以统计每个类实例化出的所有实例引用,并且可以通过这个引用操作所有类的实例。这样是不是很令人心动呢?
简单的思路如下:
不多说了,看代码:
# -*- coding=utf8 -*- import weakrefdef gen_class(): # closure variables birth_hash = [] def __new__(cls): #cls.saybefore_create() obj = object.__new__(cls) cls.save_birth_hash(obj) return obj def __init__(self): pass def method(self): print(self.__class__) @classmethod def saybefore_create(cls): print('hi,',cls) @classmethod def save_birth_hash(cls,obj): obj_ref = weakref.ref(obj) birth_hash.append(obj_ref) @classmethod def get_birth_hash(cls): return birth_hash return type('MyClass',(object,),{'__new__':__new__,'__init__':__init__,'method':method,'saybefore_create':saybefore_create,'save_birth_hash':save_birth_hash,'get_birth_hash':get_birth_hash}) And we play with it!
In [86]: MyClass = gen_class() In [87]: a = MyClass() In [88]: b = MyClass() In [89]: c = MyClass() In [90]: a.get_birth_hash() Out[90]: [<weakref at 0000000003579278; to 'MyClass' at 0000000003570CF8>, <weakref at 0000000003579368; to 'MyClass' at 00000000035707F0>, <weakref at 0000000003579458; to 'MyClass' at 0000000003570F28>] In [91]: a.get_birth_hash()[1]() == b Out[91]: True 到这里其实碰到了一个不大不小的问题,就是不能及时的清除失效的对象引用,如果直接重写 del()会破坏gc,如果有什么好的方法,请不吝告知。
EOF
1 origingodoh 2015 年 4 月 8 日 没弄清楚,难道不能直接用类变量来记录么?类变量也是所有实例共享的。 |