@property
是定义获取者的好方法。当属性是可变的时,返回的引用可以用不受类定义控制的方式修改属性。我将使用香蕉摊作为一个激励类比,但这个问题适用于任何包装容器的类。如何让类属性不可变?
class BananaStand:
def __init__(self):
self._money = 0
self._bananas = ['b1', 'b2']
@property
def bananas(self):
return self._bananas
def buy_bananas(self, money):
change = money
basket = []
while change >= 1 and self._bananas:
change -= 1
basket.append(self._bananas.pop())
self._money += 1
return change, basket
我想游客到香蕉的立场,以支付他们的香蕉。不幸的是,没有任何东西能阻止一只猴子(谁不知道更好)拿走我的香蕉。猴子不必使用内部属性_banana
,他们只是没有付钱就拿了一根香蕉。
def take_banana(banana_stand):
return banana_stand.bananas.pop()
>>> stand = BananaStand()
>>> stand.bananas
['b1', 'b2']
>>> take_banana(stand)
'b2'
>>> stand.bananas
['b1']
这个比喻有点傻,但具有可变属性的任何类不是从意外破坏的保护。在我的实际情况中,我有一个具有两个数组属性的类,它们必须保持相同的长度。随着阵列,还有什么能阻止用户从拼接第二阵列到第一和默默打破我的同等大小不变:
>>> from array import array
>>> x = array('f', [1,2,3])
>>> x
array('f', [1.0, 2.0, 3.0])
>>> x[1:2] = array('f', [4,5,6])
>>> x
array('f', [1.0, 4.0, 5.0, 6.0, 3.0])
当阵列是一个属性会发生同样的水煤浆。
我能想到的避免问题的方法有两种:
- 子类阵列,并覆盖
__setitem__
。我对此有抵触情绪,因为我希望能够在内部使用这种阵列拼接行为。 - 更改访问器以返回数组的深度拷贝。返回的数组仍然是可变的,但对其的更改不会影响父对象。
是否有解决此问题的优雅方法?我特别感兴趣的是分类财产的奇妙方式。