当前位置: 移动技术网 > IT编程>脚本编程>Python > python高级(三)—— 字典和集合(泛映射类型)

python高级(三)—— 字典和集合(泛映射类型)

2018年02月27日  | 移动技术网IT编程  | 我要评论

毛语录,imdvd,玛尔斯健身茶

本文主要内容

可散列类型

泛映射类型

字典

    (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高级系列文章目录

 

 

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网