如何在 Python 中使字典在类实例外不可变,但在类实例内可变

在 Python 中,字典是可变类型,这意味着它们可以被修改。这可能导致在类实例外对字典进行意外更改,从而导致类实例行为不符合预期。例如,假设我们有一个名为 PopulationClass 的类,它代表一个人的群体。这个类有一个名为 __population 的私有字典,它存储群体成员的信息。我们还为这个类定义了 add2populationremove_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’)`。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值