有沒有辦法返回實例屬性,但保護它免受修改?我會更具體:返回可變屬性作爲Python中的inmutable對象
我有一個Calendar
類使用由datetime.date
對象索引的內部字典,和事件ID列表作爲值(實際上int
S,但是這無關緊要)。
class Calendar:
def __init__(self):
self._dict = {}
def add_event(self, date, event):
if date in self._dict:
self._dict[date].append(event.id)
else:
self._dict[date] = [event.id]
def get_event_ids(self, date):
if date in self._dict:
return self._dict[date]
else:
return []
正如您所看到的,它非常簡單。我只想封裝列表創建和事件ID提取邏輯。但是我想保護這個日曆免受無意修改。更具體地說,不知道用戶可以真正做到這一點:
calendar = Calendar()
calendar.add_event(some_date, some_event)
event_ids = calendar.get_event_ids(some_date)
event_ids[0] = 42 # modifies the internal list in the calendar
我知道的例子似乎有點特設的,但如果你仔細想想,用戶可能希望以某種方式修改由日曆返回列表,他爲什麼期望這樣做會從內部修改日曆?
另一個(類似)事情是當我想設置一個只讀屬性。 Pythonic的方法是使用property
而不使用setter
方法,但是如果該屬性是可變的,並不能完全保護您免受外部修改。
顯而易見的答案似乎是「那麼,你爲什麼不返回一份清單的副本?」。但是:
- 列表可能會過大,而且這個方法會被調用很多次。每次複製列表可能會變得有點慢。
- 如果用戶實際上想要更改日曆,返回副本會誤導h(im/er)認爲他們可以,因爲從列表的突變中不會引發異常。
- 我認爲如果需要的話,用戶應該是花費精力/製作副本的人。
- 我想知道是否有其他方法可以達到同樣的效果。
另一種可能性是製作我自己的ConstantList
並返回。它解決了2和3,但不是1(因爲我不得不將內部可變列表複製到ConstantList
)4.另外,對於一個非常簡單的問題,它看起來太多了。
我也知道「我們都同意成年人」,並且過度保護我的實例屬性是不合理的。但我覺得我的好奇心越來越好。
你想達到什麼目的?你說你不想返回一個副本,因爲用戶可能想要修改它,但是你也不想返回真實的東西,因爲用戶可能會修改它。你不能雙方都有。您要麼返回用戶可以修改(並影響底層數據)的內容,要麼不會。 – BrenBarn
您可以返回迭代器而不是列表本身。 –
如果你想要一個不可變的集合,那麼*使用*不可變的連接(例如'tuple')。只需將'get_event_ids'修改爲'返回元組(self._dict [date])'。順便說一句:你應該真的在你的情況下使用['defaultdict(list)'](http://docs.python.org/2/library/collections.html#defaultdict-examples)並避免,這可以讓你避免所有'如果'。 – Bakuriu