在看《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 weakref
def 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
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.