python高级(三)—— 字典和集合(泛映射类型)
程序员文章站
2022-04-15 08:18:27
本文主要内容 可散列类型 泛映射类型 字典 (1)字典推导式 (2)处理不存在的键 集合 映射的再讨论 python高级——目录 文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级 可散列类型 泛映射类型 字典 ......
本文主要内容
可散列类型
泛映射类型
字典
(1)字典推导式
(2)处理不存在的键
集合
映射的再讨论
文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级
可散列类型
''' 可散列数据类型(也称可hash)————我理解"可散列"就是"可hash" 可hash的对象需要实现__hash__方法,返回hash值;另外为了与其他对象比较还需要有__eq__方法 原子不可变数据类型(str、bytes和数值类型)都是可散列的,可散列对象必须满足下列要求: (1)实现了__hash__方法,并且所得到的hash值是不变的 (2)实现了__eq__方法,用来比较 (3)若a == b 为真,那么hash(a) == hash(b)也是真 ''' # 创建类Foo,并实现__hash__和__eq__ class Foo: def __init__(self, name): self.name = name def __hash__(self): print("正在hash...") return hash(self.name) def __eq__(self, other): print("正在比较...") return self.name == other.name def __repr__(self): return self.name if __name__ == "__main__": f1 = Foo("小李") f2 = Foo("小红") f3 = Foo("小李") s = set([f1, f2, f3]) # 集合实现不重复的原理正好利用了散列表 print(s) # {小红, 小李} print( f1 == f3, hash(f1) == hash(f3)) # True True 满足可散列对象的第三个条件 |
''' 对于元组来说,只有当一个元组包含的所有元素都是可hash的情况下,它才是可hash的 ''' t1 = (1, 2, 3, [1, 2]) # 元组里的列表的值是可变的,所以不可hash try: print(hash(t1)) except Exception as e: print(e) # unhashable type: 'list' t2 = (1, 2, 3, (1, 2)) # 元组里的元素都是不可变的,并且第二层元组里面的元素也不可变,所以可hash print(hash(t2)) # 3896079550788208169 t3 = (1, 2, 3, frozenset([1, 2])) print(hash(t3)) # -5691000848003037416 |
泛映射类型
''' 泛映射类型就是广义上的对应关系,在数学中,我们将集合A对应集合B中的对应法则称为"映射"(Mapping) 同样,在python里,我们称"键值对"为映射,这其实也是一种对应法则 如果一个数据类型是映射,那么它肯定属于collections.abc.Mapping,可使用isinstance函数测试 PS: 字典是 Python 语言中唯一的映射类型。映射类型对象里哈希值(键) 和指向的对象(值)是一对多的关系。 ''' from collections import abc # 我们测试一些常用的类型是不是映射 if __name__ == "__main__": print(isinstance({}, abc.Mapping)) # True 字典是典型的键值对 print(isinstance([1, 2], abc.Mapping)) # False 列表是序列 print(isinstance((1, 2), abc.Mapping)) # False 元组是序列 print(isinstance('adfasfd', abc.Mapping)) # False 字符串也是序列 |
''' 大家可以查看_collections_abc.py源代码,里面基本的类型包含: ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator", "Hashable", "Iterable", "Iterator", "Generator", "Sized", "Container", "Callable", "Set", "MutableSet", "Mapping", "MutableMapping", "MappingView", "KeysView", "ItemsView", "ValuesView", "Sequence", "MutableSequence", "ByteString", ] ''' |
''' 如果我们自己想定义一个映射类型的对象,那么必须实现__getitem__、__iter__、__len__方法 PS:关于该部分的原理,本人暂未查看说明文档,毕竟现实中几乎不可能自定义映射;有兴趣的同志可深入钻研。 ''' class Foo(abc.Mapping): def __init__(self, name): self.name = name def __getitem__(self, item): return self.name def __iter__(self): return iter(str(self.name)) def __len__(self): return len(self.name) print(isinstance(Foo("123"), abc.Mapping)) # True |
字典
''' 字典是python内置类型中唯一的映射,先看创建字典的几种方法 1、对象创建 2、大括号 3、zip ''' if __name__ == "__main__": # 1、利用实例化对象的方法创建 a = dict(key1=1, key2=2, all=[1, 2, 3]) b = dict([('key3', 3), ('key4', 4)]) c = dict({"key5": 5, "key6": 6}) print("a:", a) # a: {'key1': 1, 'all': [1, 2, 3], 'key2': 2} print("b:", b) # b: {'key3': 3, 'key4': 4} print("c:", c) # c: {'key6': 6, 'key5': 5} # 2、直接使用大括号 d = {"key7": 7, "key8": 8} print("d:", d) # d: {'key8': 8, 'key7': 7} # 3、使用zip e = dict(zip(("key9", "key10", "key11"), [9, 10, 11])) print("e:", e) # e: {'key11': 11, 'key10': 10, 'key9': 9} |
''' 字典推导式:字典推导式的创建方法同列表推导式类似 以下直接引用《流畅的python》中的例子 ''' if __name__ == "__main__": DIAL_CODES = [ (86, 'China'), (91, 'India'), (1, 'United States'), (62, 'Indonesia'), (55, 'Brazil'), (92, 'Pakistan'), (880, 'Bangladesh'), (234, 'Nigeria'), (7, 'Russia'), (81, 'Japan'), ] country_code = {country: code for code, country in DIAL_CODES} print(country_code) # {'Russia': 7, 'Indonesia': 62, 'Brazil': 55, 'China': 86, 'India': 91, 'Bangladesh': 880, 'Pakistan': 92, 'United States': 1, 'Nigeria': 234, 'Japan': 81} code_upper = {code: country.upper() for country, code in country_code.items() if code < 66} print(code_upper) # {1: 'UNITED STATES', 7: 'RUSSIA', 62: 'INDONESIA', 55: 'BRAZIL'} |
''' 处理找不到的键 在实际场景中,当使用d[key]的方法查找数据的时候,如果找不到该键,python会抛出KeyError异常; 如果是取值操作,可以使用d.get(key, default)来解决,可以给找不到的键一个默认的值 但是如果要给更新某个不存在键对应的值的时候,就稍显麻烦了,可以使用以下方法解决: 1、用setdefault处理dict找不到的键 2、使用defaultdict对象 3、__missing__方法 ''' class Foo: def __init__(self, name=None): self.name = name def __repr__(self): return str(self.name) def setattr(self, key, value): self.__setattr__(key, value) return self if __name__ == "__main__": d1 = {} print(d1.get("key", "default")) # default 使用d.get(key, default)的方法取值 # 1、用setdefault处理dict找不到的键 d2 = {} d2.setdefault("key", [x for x in "adfaf"]) # setdefault虽然是set名字,但是是取值操作,只有当键不存在时才进行赋值,并返回该值 l = d2.setdefault("key", []) print(l) # ['a', 'd', 'f', 'a', 'f'] d2.setdefault("key2", []).extend([1, 2, 3]) # 返回空列表,所以可在后面直接使用方法extend print(d2) # {'key': 'default', 'key2': [1, 2, 3]} # 2、使用defaultdict对象 # 在python中,还有一些dict的变种类型,defaultdict为其中一种,位于collections中 from collections import defaultdict dic = defaultdict(list) # 将list的构造方法作为default_factory(只有__getitem__找不到值时调用) dic["key"].extend([1, 2, 3]) # dic中不含有"key"键,此时default_factory会被调用,创造一个空列表,并连接[1, 2, 3] print(dic["key"]) # [1, 2, 3] dic = defaultdict(Foo) # 将Foo的构造方法作为default_factory创建一个defaultdict print(dic["key"].setattr("name", "default")) # default # 3、__missing__方法 # 所有的映射类型在找不到键的时候,都会牵扯到__missing__方法;如果在__getitem__找不到键的时候,python就会自动调用它 # 另外,__missing__方法只会被getitem调用,对get或者__contains__没有影响 class My_dict(dict): def __missing__(self, key): print("正在调用__missing__...") mdict = My_dict(one=1, two=2, three=3) print(mdict) # {'two': 2, 'three': 3, 'one': 1} mdict["key"] # 正在调用__missing__... |
python高级系列文章目录