在 Python 中,字典是可变类型,这意味着它们可以被修改。这可能导致在类实例外对字典进行意外更改,从而导致类实例行为不符合预期。例如,假设我们有一个名为 PopulationClass
的类,它代表一个人的群体。这个类有一个名为 __population
的私有字典,它存储群体成员的信息。我们还为这个类定义了 add2population
和 remove_from_population
方法,用于向群体中添加和删除成员。
class PopulationClass(object):
def __init__(self):
self.__population = dict()
self.__iid_counter = 0
self.__removed_individuals = []
def add2population(self, no2add):
import random
iid_counter = self.__iid_counter
for a in range(no2add):
self.__population[iid_counter] = (iid_counter, random.sample(('F', 'M'), 1)[0], 'S')
iid_counter += 1
self.__iid_counter = iid_counter
def remove_from_population(self, key):
self.__removed_individuals.append(self.__population.pop(key))
如果我们在类实例外对 __population
字典进行更改,那么这些更改将反映在类实例中。例如,以下代码将向 __population
字典添加一个新条目:
population_instance = PopulationClass()
population_instance.add2population(5)
population = population_instance._PopulationClass__population
population[5] = 'Illegal changes'
这将导致 __population
字典包含一个名为 ``5的条目,其值为
’Illegal changes’`。这可能会导致类实例行为不符合预期。
解决方案
为了防止对 __population
字典进行意外更改,我们可以使用 collections.abc.MutableMapping
抽象基类来创建一个自定义字典类。这个自定义字典类将只允许在类实例内对字典进行修改,而在类实例外则不允许。
以下是自定义字典类的代码:
from collections.abc import MutableMapping
class ImmutableDict(MutableMapping):
def __init__(self, *args, **kwargs):
self.store = dict(*args, **kwargs)
def __getitem__(self, key):
return self.store[key]
def __setitem__(self, key, value):
raise TypeError("ImmutableDict is read-only.")
def __delitem__(self, key):
raise TypeError("ImmutableDict is read-only.")
def __iter__(self):
return iter(self.store)
def __len__(self):
return len(self.store)
然后,我们可以将这个自定义字典类作为 __population
字典的类型。这样,在类实例外对 __population
字典进行的任何更改都将被忽略。
class PopulationClass(object):
def __init__(self):
self.__population = ImmutableDict()
self.__iid_counter = 0
self.__removed_individuals = []
def add2population(self, no2add):
import random
iid_counter = self.__iid_counter
for a in range(no2add):
self.__population[iid_counter] = (iid_counter, random.sample(('F', 'M'), 1)[0], 'S')
iid_counter += 1
self.__iid_counter = iid_counter
def remove_from_population(self, key):
self.__removed_individuals.append(self.__population.pop(key))
现在,如果我们尝试在类实例外对 __population
字典进行更改,那么这些更改将被忽略。例如,以下代码将不会对 __population
字典进行任何更改:
population_instance = PopulationClass()
population_instance.add2population(5)
population = population_instance._PopulationClass__population
population[5] = 'Illegal changes'
这将导致 __population
字典仍然包含一个名为 ``5的条目,其值为
(5, ‘M’, ‘S’)`。