python 的返回值为list 的 property 绕过 setter 的问题

来源:互联网 发布:金正恩 知乎 编辑:程序博客网 时间:2024/06/14 17:44

当用property装饰一个属性,并且这个属性返回的是一个list(或者一个类,一个dict,都会有同样的情况),那么如果我们使用list的索引去访问list,setter将不起任何作用。
如下所示:

In [1]: class test(object):    ...:     a = [10,10,10]    ...:     @property    ...:     def ads(self):    ...:         print 'get'    ...:         return self.a    ...:     @ads.setter    ...:     def ads(self, val):    ...:         print 'set'    ...:         self.a = val    ...:         In [2]: test = test()In [3]: test.ads[1] = 1getIn [4]: test.adsget

可以看到,全程并没有运行setter(输出没有出现过“set”),而property的值却被改变了。

如果想要防止这种情况的发生,应该对property的值加以判断,如果不是基础类型,就使用深拷贝,能够避免这种情况的发生。
例如:

In [1]: def is_container(val):   ...:     '''判断一个变量是否为基本的类型,如果是,就意味着可以直接不需要拷贝赋值'''   ...:     return not type(val) in (int, float, long, complex, str)   ...: In [2]: import copy   ...: class test(object):   ...:     a = [10,10,10]   ...:     @property   ...:     def ads(self):   ...:         print 'get'   ...:         if not is_container(self.a):   ...:             return self.a   ...:         else:   ...:             return copy.deepcopy(self.a)   ...:     @ads.setter   ...:     def ads(self, val):   ...:         print 'set'   ...:         self.a = val   ...:         In [3]: test = test()In [4]: test.ads[1] = 1getIn [5]: test.adsgetOut[5]: [10, 10, 10]
0 0