python 字典不可变_python 不可变的字典类

问题

实验楼python挑战赛1 实现一个不可变的dict,数据只能由类初始化的时候通过参数传递,修改、添加都会抛出TypeError

解决方法

继承ABCs中的MultiMapping, 复写其中的部分方法即可。

代码

import collections

class ImmutableDict(collections.MutableMapping):

def __init__(self, **kwargs):

self.store = dict(**kwargs)

self.error = TypeError("'ImmutableDict' objects are immutable")

# self.update(dict(*args, **kwargs))

def __setitem__(self, key, value):

# 涉及到修改时会触发这个方法

raise self.error

def __iter__(self):

return iter(self.store)

def __delitem__(self, key):

# 删除时触发

raise self.error

def __getitem__(self, key):

return self.store[key]

def __len__(self):

return len(self.store)

class Get(object):

def __init__(self):

pass

def __getitem__(self, item):

return hash(item)

if __name__ == "__main__":

test = ImmutableDict(name="sun", age=22, location="China")

# test["name"] = "zhang"

# test.pop("name") TypeError will raised..

# print(test.pop("name"))

# for item in test:

# print(item)

#print(test[item])

MultiMapping 源码:

class MutableMapping(Mapping):

@abstractmethod

def __setitem__(self, key, value):

raise KeyError

@abstractmethod

def __delitem__(self, key):

raise KeyError

__marker = object()

def pop(self, key, default=__marker):

try:

value = self[key]

except KeyError:

if default is self.__marker:

raise

return default

else:

del self[key]

return value

def popitem(self):

try:

key = next(iter(self))

except StopIteration:

raise KeyError

value = self[key]

del self[key]

return key, value

def clear(self):

try:

while True:

self.popitem()

except KeyError:

pass

def update(self, other=(), **kwds):

if isinstance(other, Mapping):

for key in other:

self[key] = other[key]

elif hasattr(other, "keys"):

for key in other.keys():

self[key] = other[key]

else:

for key, value in other:

self[key] = value

for key, value in kwds.items():

self[key] = value

def setdefault(self, key, default=None):

try:

return self[key]

except KeyError:

self[key] = default

return default

MutableMapping.register(dict)

Mapping 源码:

class Mapping(Sized, Iterable, Container):

@abstractmethod

def __getitem__(self, key):

raise KeyError

def get(self, key, default=None):

try:

return self[key]

except KeyError:

return default

def __contains__(self, key):

try:

self[key]

except KeyError:

return False

else:

return True

def iterkeys(self):

return iter(self)

def itervalues(self):

for key in self:

yield self[key]

def iteritems(self):

for key in self:

yield (key, self[key])

def keys(self):

return list(self)

def items(self):

return [(key, self[key]) for key in self]

def values(self):

return [self[key] for key in self]

# Mappings are not hashable by default, but subclasses can change this

__hash__ = None

def __eq__(self, other):

if not isinstance(other, Mapping):

return NotImplemented

return dict(self.items()) == dict(other.items())

def __ne__(self, other):

return not (self == other)

分析两个问题:

.get 的时候究竟发生了什么?

.pop 的时候发生了什么?

尝试进行断点调试:

尝试

get 跳转到了Mapping中的get

image.png

image.png

注意其中的self就是我们实例化的immutableDict类

结论: .get显示定义是在Mapping中,但是Mapping又把这个方法的实现抛给了子类,事实上,就是调用了 immutableDict.getitem中的方法。

所以我们在get 会触发我们在 immutableDict.getitem中定义的异常

pop 也就很类似了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值