缘起
话接上回,说是接手了一个82年的拉菲Python项目,这次又发现了一个新坑
项目中用了一个上下文类,用于存储本次请求的一些数据,在开发过程中我想把这个上下文类dump成json,详细分析里面的数据,然而发现上下文类的行为不符合预期
症状
上下文类大概是这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Context(): def __init__(self): self._input_json = None self._result_dict = dict()
@property def input_json(self): print 'get _input_json' return self._input_json
@input_json.setter def input_json(self, input_json): print 'set _input_json %s ' % input_json self._input_json = input_json
@property def result_dict(self): print 'get _result_dict' return self._result_dict
@result_dict.setter def result_dict(self, result_dict): print 'set _result_dict %s ' % result_dict self._result_dict = result_dict
def to_dict(self): tmp = {} for k, v in self.__dict__.items(): if k.startswith('_'): tmp[k] = v return tmp
|
测试之后发现,结果明显不符合预期,两个属性只输出了一个
1 2 3 4 5 6 7 8
| >>> from test_property import Context >>> c = Context() ... c.input_json = {'a': 1} ... c.result_dict['b'] = 2 ... get _result_dict >>> c.to_dict() {'_input_json': None, '_result_dict': {'b': 2}}
|
分析
看测试代码我们可以发现,在访问result_dict属性的时候,property是工作正常的(有对应的print)
但是对应设置input_json的时候, 却没有看到对应的print输出
所以可以断定,此处的property工作不正常。
仔细看代码后,我发现Context是旧式类。可以看到,A, B, C三中类的写法,其中A和B都是旧式类<type 'classobj'>, C是新式类。(旧式类只在Python2中存在)。
我们这里Context的写法和B是一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| >>> class A: ... pass ... ... class B(): ... pass ... ... class C(object): ... pass ... >>> type(A) <type 'classobj'> >>> type(B) <type 'classobj'> >>> type(C) <type 'type'>
|
然后自然就怀疑旧式类对property装饰器的支持存在问题。
一通google之后,确定旧式类是不支持property。

确切地说,是对property的支持不完整,具体来说有以下3点。
- 支持property的getter
- 不支持property的setter
- 不支持property的赋值保护
参考