精华内容
下载资源
问答
  • Python中的映射类型详解

    千次阅读 2020-07-18 13:50:11
    这些抽象基类的主要作用事作为形式化的文档,它们定义了构建映射类型所需要的最基本的接口.然后它们还可以跟isinstance一起被用来判定某个数据是不是广义上的映射类型: from collections.abc import

    泛映射类型

    collections.abc模块中有Mapping和MutableMapping这两个抽象基类,它们的作用事为dict和其他类似的类型定义形式接口
    非抽象映射类型一般不会直接继承这些抽象基类,它们会直接对dict或者是collections.UserDict进行扩展.这些抽象基类的主要作用事作为形式化的文档,它们定义了构建一个映射类型所需要的最基本的接口.然后它们还可以跟isinstance一起被用来判定某个数据是不是广义上的映射类型:

    from collections.abc import Mapping, MutableMapping

    标准库里的所有映射类型都是利用dict来实现的,因此它们有个共同的限制,即只有<可散列的>数据类型才能用作这些映射里的键.

    什么是可散列的数据类型?

    如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,而且这个对象需要实现__hash__()方法.

    另外可散列对象还要有__eq__()方法,这样才能跟其他键作比较.如果两个可散列对象是相等的,那么它们的散列值一定是一样的.

    原子不可变数据类型(str,bytes和数值类型)都是可散列类型,frozenset也是可散列的,因为根据其定义,frozenset里只能容纳可散列类型.

    元组的话,只有当一个元组包含的所有元素都是可散列类型的情况下,它才是可散列的.

    tt = (1, 2, (30, 40))
    print(hash(tt))  # 8027212646858338501
    tl = (1, 2, [30, 40])
    # print(hash(tl))  # TypeError: unhashable type: 'list'
    tf = (1, 2, frozenset([30, 40]))
    print(hash(tf))  # 985328935373711578
    

    一般来讲,用户自定义的类型的对象都是可散列的,散列值就是它们的id()函数的返回值,所以所有这些对象在比较的时候都是不相等的.

    如果一个对象实现了__eq__方法,并且在方法中用到了这个对象的内部状态的话,那么只有当所有这些内部状态都是不可变的情况下,这个对象踩死可散列的.

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    class A:
        def __init__(self, a_):
            self.a = a_
    
    
    class B:
        def __init__(self, a_):
            self.a = a_
    
        def __hash__(self):
            return hash(self.a)
    
        def __eq__(self, other):
            return hash(self) == hash(other)
    
    
    a1 = A(1)
    a2 = A([1, 2, 3])
    print(hash(a1))  # -9223371857585079499
    print(hash(a2))  # 179269859620
    
    b1 = B(1)
    b2 = B([1, 2])
    print(hash(b1))  # 1
    # print(hash(b2))  # TypeError: unhashable type: 'list'
    
    # 根据这些定义,字典提供了很多种构造方法.
    a = dict(one=1, two=2, three=3)
    b = {'one': 1, 'two': 2, 'three': 3}
    c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
    d = dict([('one', 1), ('two', 2), ('three', 3)])
    e = dict({'one': 1, 'two': 2, 'three': 3})
    print(a == b == c == d == e)
    

    字典推导式

    字典推导可以从任何以键值对作为元素的可迭代对象中构建出字典

    STUDENTS = [
        ("孙悟空", 100),
        ("猪八戒", 90),
        ("沙和尚", 80),
        ("二郎神", 70),
        ("哪吒", 60),
        ("诸葛亮", 50),
    ]
    student = {name: number for name, number in STUDENTS}
    print(student)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50}
    student2 = {name: number for name, number in student.items() if number > 60}
    print(student2)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70}
    

    常见的映射方法

    dict.update(m, [**kargs])方法处理参数m的方式,是典型的’鸭子类型’,函数首先检查m是否有keys方法,如果有,那么update函数就把它当作映射对象来处理.

    否则,函数会退一步,转而把m当作包含了键值对(key, value)元素的迭代器.python里大多数映射类型的构造方法都采用了类似的逻辑,因此你既可以用一个映射对象来新建一个映射对象,也可以用包含(key, value)元素的可迭代对象来初始化一个映射对象.

    print(student)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50}
    student.update({"小白龙": 80, "唐僧": 90})
    print(student)  # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50, '小白龙': 80, '唐僧': 90}
    student.update([("李世民", 90), ("朱元璋", 85)])
    # {'孙悟空': 100, '猪八戒': 90, '沙和尚': 80, '二郎神': 70, '哪吒': 60, '诸葛亮': 50, '小白龙': 80, '唐僧': 90, '李世民': 90, '朱元璋': 85}
    print(student)
    

    用setdefault处理找不到的键

    当字典d[k]不能找到正确的键的时候,Python会抛出异常,这个行为符合Python所信奉的’快速失败’哲学.

    也许每个Python程序员都知道可以用d.get(k, default)来代替d[k],给找不到的键一个默认的返回值.这比处理KeyError要方便不少.

    但是要更新某个键对应的值的时候,不管用__getitem__还是get都会不自然,而且效率低.

    例1

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    import re
    
    WORD_RE = re.compile(r'\w+')
    index = {}
    with open('./word', encoding='utf-8') as fp:
        for line_no, line in enumerate(fp, 1):
            # re.finditer(string) 返回string中所有与pattern相匹配的全部字串,返回形式为迭代器。
            for match in WORD_RE.finditer(line):
                word = match.group()  # 匹配到的单词
                column_no = match.start() + 1  # 单词首字目所在的位置,从1开始
                location = (line_no, column_no)  # (行号, 列号)
                # 这其实是一种很不好的实现,这样写只是为了证明论点
                occurrences = index.get(word, [])  # 提取word出现的情况,如果还没有它的记录,返回[].
                occurrences.append(location)  # 把单词出现的位置添加到列表的后面.
                index[word] = occurrences  # 把新的列表放回字典中,这又牵扯到一次查询操作.
        # 以字母顺序打印出结果
        # sorted函数的key=参数没有调用str.upper,而是把这个方法的引用传递给sorted函数,这样在排序的时候,单词会被规范成统一格式.
        for word in sorted(index, key=str.upper):  # 将方法用作一等函数
            print(word, index[word])
    
    index_ = {}
    
    with open('./word', encoding='utf-8') as fp:
        for line_no, line in enumerate(fp, 1):
            for match in WORD_RE.finditer(line):
                word = match.group()
                column_no = match.start() + 1
                location = (line_no, column_no)
                index_.setdefault(word, []).append(location)
        for word in sorted(index_, key=str.upper):
            print(word, index_[word])
    

    dict.setdefault(key, []).append(new_value)

    获取单词的出现情况列表,如果单词不存在,把单词和一个空列表放进映射,然后返回这个空列表,这样就能在不进行第二次查找的情况下更新列表了.

    也就是说,和下面的代码效果一样

    if key not in dict:
        dict[key] = []
    dict[key].append(new_value)
    

    只不过,后者至少要进行两次键查询,如果键不存在的话,就是三次.而setdefault只需要一次就可以完成整个操作

    映射的弹性键查询

    有时候为了方便起见,就算某个键在映射里不存在,我们也希望在通过这个键读取值的时候能得到一个默认值.有两个途径能帮我们达到这个目的,一个是通过defaultdict这个类型而不是普通的dict,另一个是给自己定义一个dict的子类,然后再子类中实现__missing__方法.

    在用户创建defalutdict对象的时候,就需要给它配置一个为找不到的键创造默认值的方法.
    具体而言,在实例化一个defaultdict的时候,需要给构造方法提供一个可调用对象,这个可调用对象会在__getitem__碰到找不到的键的时候被调用,让__getitem__返回某种默认值

    比如,我们新建了这样一个字典:dd = defaultdict(list),如果键’new-key’在dd中还不存在的话,表达式dd[‘new-key’]会按照以下的步骤来执行:

    1.调用list()来建立一个新列表
    2.把这个新列表作为值,'new-key’作为它的键,放到dd中
    3.返回这个列表的引用

    而这个用来生成默认值的可调用对象存放在名为default_factory的实例属性中

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    from collections import defaultdict
    
    # 把list构造方法作为default_factory来创建一个defaultdict
    index_dd = defaultdict(list)
    
    with open('./word', encoding='utf-8') as fp:
        for line_no, line in enumerate(fp, 1):
            for match in WORD_RE.finditer(line):
                word = match.group()
                column_no = match.start() + 1
                location = (line_no, column_no)
                """
                如果index_dd并没有word记录,那么default_factory会被调用,为查询步到的键创造一个值.
                这个值在这里是一个空列表,然后这个空列表会被赋值给index_dd[word],继而被当作返回值返回.
                因此.append(location)操作总能成功
                """
                index_dd[word].append(location)
        for word in sorted(index_, key=str.upper):
            print(word, index_dd[word])
    

    如果在创建defaultdict的时候没有指定default_factory,查询不存在的键会触发KeyError
    defaultdict里的default_factory只会在__getitem__里被调用,在其他的方法里完全不会发挥作用.
    比如dd[k]这个表达式会调用default_factory创造某个默认值,而dd.get(k)则会返回None

    所有这一切背后的功臣其实是特殊方法__missing__.它会在defaultdict遇到找不到的键的时候调用default_factory,而实际上这个特性是所有映射类型都可以选择去支持的.

    所有的映射类型在处理找不到的键的时候,都会牵扯到__missing__方法.这也是这个方法被称作’'missing的原因.

    虽然基类dict没有定义这个方法,但是dict是知道有这个东西存在的.也就是说,如果有一个类继承了dict,然后这个继承类提供了__missing__方法,那么在__getitem__碰到找不到的键的时候,Python就会自动调用它,而不是抛出KeyError异常.

    __missing__方法只会被__getitem__调用,对get或者__contains__这些方法的使用没有影响.

    class StrKeyDict(dict):  # 继承dict
        """
        如果要自定义一个映射类型,更合适的策略其实是继承collections.UserDict类.这里我们从dict继承,
        只是为了演示__missing__是如何被dict.__getitem__调用的
        """
    
        def __missing__(self, key):
            """
            为什么isinstance(key, str)是必须的?
            如果没有这个测试,当str(key)不是一个存在的键,代码就会陷入无限递归.这是因为__missing__的最后一行中的self[str(key)]会调用
            __getitem__,而这个str(key)又不存在,于是__missing__又会被调用.
            """
            if isinstance(key, str):  # 如果找不到的键本身就是字符串,那就抛出KeyError异常
                raise KeyError(key)
            # 如果找不到的键不是字符串,那么就把它转换成字符串再进行查找
            return self[str(key)]
    
        def get(self, key, default=None):
            """
            get方法把查找工作用self[key]的形式委托给__getitem__,这样在宣布查找失败之前,还能通过__missing__再给某个键一个机会
            """
            try:
                return self[key]
            except KeyError:
                # 如果抛出KeyError,那么说明__missing__也失败了,于是返回default.
                return default
    
        def __contains__(self, item):
            """
            为了保持一致性,__contains__方法也是必须的.这是因为k in d这个操作会调用它,但是我们从dict继承到的__contains__方法[不会]在找不到键的时候
            调用__missing__方法.__contains__里还有个细节,就是我们这里没有用更具Python风格的方式--item in self--来检验是否存在,因为那也会导致
            __contains__被递归调用,为了避免这一情况,这里采取了更显式的方法,直接在这个self.keys()里查询.
    
            像k in my_dict.keys()这种操作在Python3中是很快的,而且即便映射类型对象很庞大也没关系.这因为dict.keys()的返回值是一个"视图".
            视图就像一个集合,而且跟字典类似的是,在视图里查找一个元素的速度很快.
            Python2中的dict.keys()返回的则是一个列表,它在处理体积大的对象的时候效率不会太高,因为k in my_list操作需要扫描整个列表.
            """
            # 先安装传入键的原本的值来查找,如果没找到,再用str()方法把键转换成字符串再查找一次.
            return item in self.keys() or str(item) in self.keys()
    
    
    d = StrKeyDict([('2', 'two'), ('4', 'four')])
    print(d['2'])  # two
    print(d[4])  # four
    # print(d[1])  # KeyError: '1'
    
    print(d.get('2'))  # two
    print(d.get(4))  # four
    print(d.get(1))  # None
    
    print(2 in d)  # True
    print(1 in d)  # False
    

    字典的变种

    from collections import OrderedDict, ChainMap, Counter, UserDict
    

    collections.OrderedDict

    这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的.OrderedDict的popitem方法默认删除并返回的是字典里的最后一个元素.

    但是如果像my_dict.popitem(last=False)这样调用它,那么它删除并返回第一个被添加进去的元素.

    collections.ChainMap

    该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止.

    这个功能在给有嵌套作用域的语言做解释器的时候很有用,可以用一个映射对象来代表一个作用域的上下文.

    例如下面这个Python变量查询规则:

    import builtins
    
    py_lookup = ChainMap(locals(), globals(), vars(builtins))
    
    """
    collections.Counter
    这个映射类型会给键准备一个整数计数器.每次更新一个键的时候都会增加这个计数器.所以这个类型可以用来给可散列列表对象计数,
    或者是当成多重集来用--多重集合就是集合里的元素可以出现不止一次.Counter实现了+和-运算符用来合并记录,还有像most_common([n])这类很有用的方法.
    most_common([n])会按照次序返回映射里最常见的n个键和它们的计数.
    下面的小例子利用Counter来计算单词中各个字母出现的次数:
    """
    ct = Counter('abracadabra')
    print(ct)  # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
    ct.update('aaaaazzz')
    print(ct)  # Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
    print(ct.most_common(2))  # [('a', 10), ('z', 3)]
    

    collections.UserDict

    这个类其实就是把标准的dict用纯Python又实现了一遍.跟前三者不同,UserDict是让用户继承写子类的.下面就来试试:

    就创造自定义映射类型来说,以UserDict为基类,总比以普通的dict为基类要来得方便.这体现在,我们能够改进上面的StrKeyDict类,使得所有的键都存储为字符串类型.

    而更倾向于从UserDict而不是从dict继承的主要原因是,后者有时会在某些方法的实现上走一些捷径,导致我们不得不在它的子类中重写这些方法,但是UserDict就不会带来这些问题.

    另外一个需要注意的地方是UserDict并不是dict的子类,但是UserDict有一个叫做data的属性,是dict的实例,这个属性实际上是UserDict最终存储数据的地方.

    这样做的好处是,比起上面的例子,UserDict的子类就能在实现__setitem__的时候避免不必要的递归,也可以让__contains__里的代码更简洁.

    下面的雷子不但把所有的键都以字符串的形式存储,还能处理一些创建或者更新实例时包含非字符串类型的键这类意外情况.

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    class StrKeyDict_U(UserDict):  # StrKeyDict_U是对UserDict的拓展
        def __missing__(self, key):
            if isinstance(key, str):
                raise KeyError(key)
            return self[str(key)]
    
        def __setitem__(self, key, value):
            # 把所有的键都转换成字符串.由于把具体的实现委托给了self.data属性,这个方法写起来也不难.
            self.data[str(key)] = value
    
        def __contains__(self, item):
            # 这里可以放心假设所有已经存储的键都是字符串.
            # 并且可以直接在self.data上查询
            return str(item) in self.data
    

    因为UserDict继承的是MutableMapping,所以StrKeyDict_U里剩下的那些映射类型的方法都是从UserDict、MutableMapping和Mapping这些超类继承来的.

    特别是最后的Mapping类,它虽然是一个抽象基类(ABC),但它却提供了好几个实用的方法.

    MutableMapping.update

    这个方法不但可以为我们所直接利用,它还用在__init__里,然构造方法可以利用出入的各种参数(其他映射类型、元素是(key, value)对的可迭代对象和键值参数)来新建实例.因为这个方法在背后是用self[key] = value来添加新值的,所以它其实是在使用我们的__setitem__方法

    Mapping.get

    在StrKeyDict中,我们不得不改写get方法,好让它的表现跟__getitem__一致.而在StrKeyDict_U中就没有这个必要了,因为它继承了Mapping.get方法,这个方法的实现方式跟StrKeyDict.get是一模一样的.

    不可变映射类型

    标准库里的所有映射类型都是可变的,但是有时候我们需要限制用户的修改从Python3.3开始,types模块中引入了一个封装类名叫MappingProxyType.如果给这个类一个映射,它会返回一个只读的映射视图.

    虽然是个只读视图,但是它是动态的.这意味着如果对原映射做出了改动,我们通过这个视图可以观察到,但是无法通过这个视图对原映射做修改.

    from types import MappingProxyType
    d = {1: 'A'}
    d_proxy = MappingProxyType(d)
    print(d_proxy)  # {1: 'A'}
    print(d_proxy[1])  # A   d中的内容可以通过d_proxy看到
    # 但是通过d_proxy并不能做任何修改
    # d_proxy[2] = 'X'  # TypeError: 'mappingproxy' object does not support item assignment
    d[2] = 8
    # d_proxy是动态的,也就是说对d所做的任何改动都会反馈到它的上面
    print(d_proxy[2])  # 8
    
    展开全文
  • 关于python中的映射类型

    千次阅读 2019-09-07 20:04:08
    下面介绍一下python的数据类型相关的题目 ...解析:映射是一种关联式的容器类型,它存储了对象与对象之间映射关系,字典是python里唯一的映射类型,它存储了键值对的关联,是由键到键值的映射关系。 ...

    下面介绍一下python的数据类型相关的题目
    1.下列哪种类型是python的映射类型?
    选项:str list tuple dict
    答案:dict
    解析:映射是一种关联式的容器类型,它存储了对象与对象之间映射关系,字典是python里唯一的映射类型,它存储了键值对的关联,是由键到键值的映射关系。

    展开全文
  • 映射类型是一类可迭代的键-值数据项的组合...在python3.1后,还引入了一种有序的映射类型:collections.OrderedDict. 特点: 1.只有可哈希运算的对象可用于映射类型中的键,因此,内置的固定的数据类型都可以用作...

    映射类型是一类可迭代的键-值数据项的组合,提供了存取数据项及其键和值的方法,在python3中,支持两种无序的映射类型:内置的dict和标准库中的collections.defaultdict类型。
    在python3.1后,还引入了一种有序的映射类型:collections.OrderedDict.

    特点:
    • 1.只有可哈希运算的对象可用于映射类型中的键,因此,内置的固定的数据类型都可以用作映射类型中的键(内置固定的类型都可进行哈希运算),目前接触到的固定数据类型有:int、float、complex、bool、str、tuple、frozenset
    • 2.每个键相关联的值可以是任意对象;
    • 3.映射类型也是可迭代的(iterable)。
    • 4.映射类型可以使用比较操作符进行比较,可以使用成员关系符in/not in和内置len()函数。

    1.dict(字典)

    dict数据类型是一种无序的、可变的组合数据类型,其中包含0-n个键值对,键是指向可哈希运算的对象的引用,值可以指向任意对象的引用。由于键是可哈希运算的对象引用,因此保证了键的唯一性;由于dict是可变的,因此可以对dict进行数据项的添加和移除操作;由于dict是无序的,因此没有索引,也不能使用分片操作符进行操作。

    dict的创建

    1.dict()可以作为一个函数调用,此时创建一个空dict:

    >>> dict()
    {}
    >>> 

    dict()中传入一个映射类型的参数时,将返回以该参数为基础的字典,如:

    >>> d1 = {"key1":"value1","key2":"value2"}
    >>> dict(d1)
    {'key1': 'value1', 'key2': 'value2'}
    >>> 

    dict() 还可以接受序列类型的参数,但是前提是序列中的每一个数据项本身是一个包含两个对象的序列,第一个用作键,第二个用作值,如:

    >>> d1 = dict((("k1","v1"),("k2","v2")))   #使用元组创建
    >>> d1
    {'k1': 'v1', 'k2': 'v2'}
    >>> 
    >>> d1 = dict([("k1","v1"),("k2","v2")])   #使用序列创建
    >>> d1
    {'k1': 'v1', 'k2': 'v2'}
    >>> 

    dict() 中还可以关键字参数进行创建,其中键作为关键字,值作为关键字的值,如:

    >>> dict(id=1,name="zhangsan",age=23)
    {'id': 1, 'name': 'zhangsan', 'age': 23}
    >>> 

    注意:关键字必须为有效的python标识符

    2.使用花括号创建dict,空{}会创建一个空的dict,非空dict由多个项组成,每一项由逗号分隔,其中每一项都使用K:V 的形式创建,如:

    >>> dict2 = {"name":"kobe","age":33,"num":24}
    >>> dict2
    {'name': 'kobe', 'age': 33, 'num': 24}
    >>> 

    3.使用字典内涵创建字典(单独列出)

    常用操作符和方法

    操作符:
    [] 用于存取dict中的某一个单值,如:

    >>> d =dict(k1="value1",k2="value2")
    >>> d["k1"]
    'value1'
    >>> 

    =:用于添加或替换dict中某一项,如:

    >>> d = dict()
    >>> d["k1"]="V1"
    >>> d
    {'k1': 'V1'}
    >>> 

    如果存在键k1,则使用“V1”替换原来“k1”的值。

    注意:dict是无序的,不能使用分片操作符[],但这里的[]并非分片操作符。

    del语句:删除某一项,如:

    >>> d
    {'k1': 'value1', 'k2': 'value2'}
    >>> del d["k1"]
    >>> d
    {'k2': 'value2'}
    >>> 

    如果存在指定的键,则移除,如果不存在,则会出现KeyError 异常。
    in/not in:通过键进行成员关系判断,如:

    >>> "k2" in d
    True
    >>> "value2" in d  #通过键进行判断,而不是值
    False
    >>> 

    方法:
    d.clear() :移除dict中所有项;
    d.copy():返回d的浅拷贝:

    >>> d = dict(id = 1,name = "zhangsan",age = 23,gendor = "男")
    >>> d2 = d.copy()
    >>> d2
    {'id': 1, 'name': 'zhangsan', 'age': 23, 'gendor': '男'}
    >>>

    d.fromkeys(s,v):返回一个dict,该dict的键为序列s中的项,值为None或者v,参数v可选:

    >>> d.fromkeys(["k1","k2","k3"],0)
    {'k1': 0, 'k2': 0, 'k3': 0}
    >>> 

    d.get(k):通过给定的键返回对应的值,如果不存在就返回None:

    >>> d.get("name") 
    'zhangsan'
    >>>

    d.get(k,v):通过给定的键返回对应的值,如果不存在就返回v.
    d.items():返回d中所有键值对的字典视图;

    >>> d.items()
    dict_items([('id', 1), ('name', 'zhangsan'), ('age', 23), ('gendor', '男')])
    >>>

    字典视图,是一个只读的并且可迭代的itreable对象,存放了字典的键和值。

    d.keys():返回d中所有键的视图

    >>> d.keys()
    dict_keys(['id', 'name', 'age', 'gendor'])
    >>> 

    d.pop(k):返回并移除d中的k和k对应的值,如果不存在k,出现KeyError异常:
    d.popitem():返回并移除d中任意一个键值对,如果d为空,则产生KeyError异常:

    >>> d.pop("age")     
    23
    >>> d.popitem() 
    ('gendor', '男')
    >>> d.items()
    dict_items([('id', 1), ('name', 'zhangsan')])
    >>> 

    d.setdefalut(k,v):返回d中k的值,如果不存在,就在d中插入k-v:

    >>> d.setdefault("gender","男") 
    '男'
    >>> d.items()
    {'id': 1, 'name': 'zhangsan', 'gender': '男'}
    >>> 

    d.update(i):将i中每个尚未包含在d中的k-v添加到d中,或者将d中包含了i中k-v的键,使用i中的v进行替换,但是i中每一项只能为2个长度,否则出现ValueError异常,也可以使用关键字参数:

    >>> d.update([("weight"),(23)])
    Traceback (most recent call last):
      File "<pyshell#231>", line 1, in <module>
        d.update([("weight"),(23)])
    ValueError: dictionary update sequence element #0 has length 6; 2 is required
    >>> 
    >>> d.update(["kv"])  #ok
    >>> d
    {'id': 1, 'name': 'zhangsan', 'gender': '男', 'k': 'v'}
    >>> 
    >>> d.update(gender = "男")  #关键字参数
    >>> d
    {'id': 1, 'name': 'zhangsan', 'age': 23, 'gender': '男'}
    >>> 

    d.values():返回d中所有值的视图:

    >>> d.values()
    dict_values([1, 'zhangsan', '男'])
    >>> 

    掌握这些基本方法后,就可以对dict进行操作了。

    操作dict

    1.迭代dict:

    可以使用d.items(),d.values(),d.keys()迭代dict,如:

    >>> for item in d.items():    #使用itmes()迭代
             print(item[0],item[1])
    id 1
    name zhangsan
    gender 男
    k v
    >>> 
    >>> for key in d.keys():   #使用keys()迭代
             print(key,d.get(key))
    id 1
    name zhangsan
    gender 男
    k v
    >>> 
    >>> for value in d.values():    #使用values()迭代
             print(value)
    1
    zhangsan
    男
    v
    >>> 

    也可以直接使用dict来遍历,等同于使用d.keys(),如:

    >>> for key in d:
        print(key) 
    id
    name
    gender
    k

    字典视图

    在使用dict.items(),dict.keys(),dict.vaules()时,返回的是一个字典视图,字典视图也可以当做一个iterable,除此之外,字典视图还能支持一些类似集合的操作,如:
    d1v & d2v:返回d1和d2的交集;
    d1v | d2v:返回d1和d2的并集;
    d1v - d2v:返回包含在d1但不包含在d2中的数据项的集合
    d1v ^ d2v:返回d1和d2的对称差集,即交集之外数据项的集合;

    >>> d1 = {}.fromkeys("ABCD",0)
    {'A': 0, 'B': 0, 'C': 0, 'D': 0}
    >>> d2 = {}.fromkeys("ABCDE",0)
    {'A': 0, 'B': 0, 'C': 0, 'D': 0, 'E': 0}

    使用场景

    1.dict的键是唯一的,因此可以用来存放排他性项的数,这里使用dict.get(k,v)方法来统计一个str中各个字母出现的个数:

    >>> s = "hi,my name is James,nice to meet you"   #字符串
    >>> d = {}     #创建一个空dict字典
    >>> for letter in s.lower():   #将str全部变为小写后进行遍历
            d[letter]=d.get(letter,0)+1    #每次遍历的str作为K,将值+1
    >>> for element in d:
        print("the \"{0}\" occurs {1} times".format(element,d[element]))
    the "h" occurs 1 times
    the "i" occurs 3 times
    the "," occurs 2 times
    the "m" occurs 4 times
    the "y" occurs 2 times
    the " " occurs 6 times
    the "n" occurs 2 times
    the "a" occurs 2 times
    the "e" occurs 5 times
    the "s" occurs 2 times
    the "j" occurs 1 times
    the "c" occurs 1 times
    the "t" occurs 2 times
    the "o" occurs 2 times
    the "u" occurs 1 times
    >>> 

    在这个例子中,通过dict.get(K,V)将遍历的字母和出现的次数分别作为键和值,如果第一次不存在,则d[letter]=get(letter,0)使用默认值0,之后每次都会对letter+1。如果不使用dict.get(k,v),也可以按照如下方式进行:

    >>> for letter in s.lower():
            if letter not in d:
                d[letter] = 0
            d[letter]+=1

    dict.get(k,v)显然是更加巧妙。

    字典内涵

    在之前总结序列类型和集合类型时,为方便创建长的列表和集合,有了列表内涵和集合内涵的概念,同样的,python还提供了字典内涵这个语法用来创建非常长的字典,字典内涵是一个循环表达式,格式如下:
    {keyexpression:valueexpression for key,value in iterable if condition}

    2.collections.defaultdict(默认字典)

    defaultdict是dict的子类,它支持dict的所有的操作和方法。和dict的不同之处在于,如果dict中不包含某一个键,则通过dict[x]取值时出现KeyError异常,但是如果是defaultdict,则会创建一个新的项,键为该键,值为默认值。

    创建collections.defaultdict

    创建collections.defaultdict时,通过collections.defaultdict(),根据参数可以有两种方式进行创建:

    * 1.使用参数类型来创建:
    >>> import collections
    >>> cd1 = collections.defaultdict(int)
    >>> cd2 = collections.defaultdict(list)
    >>> cd3 = collections.defaultdict(str)
    >>> cd1["x"]
    0
    >>> cd2["x"]
    []
    >>> cd3["x"]
    ''
    >>> 

    这里分别使用了int、list、str,他们的默认值分别为0,[],”

    * 2.使用函数名来创建:
    >>> def name():
        return 'zhangsan'
    >>> cd4 = collections.defaultdict(name)
    >>> cd4["x"]
    'zhangsan'
    >>> 

    通过这种方式,可以使默认字典的默认值更加灵活。
    需要注意的是,collections.defaultdict()可以不传入参数或者传入None,但是如果这样,则不支持默认值,比如:

    >>> cd5 = collections.defaultdict()
    >>> cd5["x"]
    Traceback (most recent call last):
      File "<pyshell#254>", line 1, in <module>
        cd5["x"]
    KeyError: 'x'
    >>> 

    有了collections.defaultdict,可以代替dict中的get(k,v)setdefault()方法了。

    展开全文
  • Mapping,映射,相当于关系型数据库创建语句,定义文档字段及其类型、索引与存储方式。通常会涉及如下方面: 文档中哪些字段需要定义成全文索引字段。...1.1 映射类型 Elasticsearch支持meta-fields...

    Mapping,映射,相当于关系型数据库创建语句,定义文档字段及其类型、索引与存储方式。通常会涉及如下方面:

    • 文档中哪些字段需要定义成全文索引字段。
    • 文档中哪些字段定义为精确值,例如日期,数字、地理位置等。
    • 文档中哪些字段需要被索引(能通过该字段的值查询文档)。
    • 日期值的格式。
    • 动态添加字段的规则定义等。

    1、类型映射概述
    1.1 映射类型
    Elasticsearch支持meta-fields、fields or properties两种映射类型,将决定文档的索引方式。

    • Meta-fields
      元数据字段用于定义文档的元数据字段的特征,文档的元数据字段主要包括_index、_type、_id、_source这4个字段。

    • Fields or properties
      属性字段列表,通过properties字段定义整个文档有效载荷的各字段的数据类型、分词器等属性。
      映射类型,可以理解为以何种方式来定义索引中一个类型的字段集。

    1.2 数据类型
    每一个字段都会指定一个数据类型,数据类型通常如下:
    简单类型,例如text、keyword、date、long、double、boolean、ip
    复合类型,诸如object(json)、netsed.
    特殊类型,诸如geo_point、geo_shape(地图相关类型)、completion。
    后续章节会单独重点剖析elasticsearch所支持的数据类型。

    1.3 映射保护机制
    es提供如下参数来限制es的行为:

    • index.mapping.total_fields.limit t
      索引中允许定义的最大字段(属性)个数,默认为1000。
    • index.mapping.depth.limit
      字段级联的最大深度,默认为20。
    • index.mapping.nested_fields.limit
      一个索引最多包含字段类型为nested的个数,默认为50。

    1.4 动态映射机制
    与关系型数据库不同的是,一个type(对应关系型数据库的表)中的字段可以在使用过程中动态添加。具体的动态映射机制,将在后续文章中单独结束。

    1.5 更新已有映射定义
    es不支持直接修改已索引的已存在的字段映射,因为修改字段映射,意味着已索引的数据生效,可以使用别名机制来修改字段的名称,如果需要修改已存在字段的映射,建议重新创建一个索引,再使用reindex API迁移数据。

    1.6 索引、type组织方式
    索引在创建时,Elasticsearch6.x版本只支持一个映射类型,而7.x版本后将完成删除映射类型。es5.x中一个索引包含多个type的情况再6.x版本将继续支持查询,7.0版本后,API将完成移除与多类型相关的API。

    Elasticsearch6.x版本后为什么不继续对单一索引库提供多类型支持呢?
    当初,为了方便理解es,通常与关系型数据库进行类比,例如es中的index(索引)相当于关系型数据库的database,而类型(type)相当于关系型数据库中的table。其实这是一个错误的比喻。在关系型数据库中,表是相互独立的,一个表中的列名与另外一个表中的列名相同是没有关系的,但对于es的类型映射定义,情况并非如此。

    在es单一索引中,不同映射类型(type)具有相同名称的字段在内部都是由同一个Lucence字段来存储,这也就意味着同一个索引内不同的类型,如果出现名字相同的字段,其数据类型也必须相同。更重要的是,存储在同一索引中具有很少或没有共同字段的不同类型(实体)会导致数据稀疏,大大降低Lucece高效压缩文档的能力,影响其检索性能。

    基于上述各种原因,故es将在后续版本中不支持一个索引中定义多个类型。

    2、meta-field(元字段)
    每个文档都有与之关联的元数据,例如_index、mapping _type和_id元字段。在创建映射类型时,可以定制其中一些元字段的行为。

    • identity meta-fields(表明文档身份的元字段)
    1. _index
      文档所在的索引,类似于关系型数据库的database。
    2. _uid
      _type与_id的组合,文档的唯一标识。
    3. _type
      文档映射类型。
    4. _id
      文档的_id值。
    • document source meta-fields
    1. _source
      文档的原始json数据。
    2. _size
      文档_souce字段的字节长度,需要插件:mapper-size plugin。
    • indexing meta-fields
    1. _all
      将所有字段映射成一个_all字段,在6.0.0版本后废弃,可以使用copy_to来定义需要聚合的字段。
      _field_names
      _field_names字段,用于索引文档中包含除null之外的任何值的每个字段的名称。exist查询使用这个字段来查找对于特定字段具有或不具有任何非空值的文档,也就是该字段记录的是字段值不为null的所有字段名称。当前版本,_field_names字段不包含启用了doc_values、norm的字段,对于启用doc_values或norm的字段,exist查询仍然可用,但不会使用_field_names字段。
      注:禁用_field_names通常是不必要的,因为它不再承载以前的索引开销。如果你有很多禁用doc_value和norm的字段,并且你不需要使用这些字段执行exist查询,你可能想禁用_field_names,你可以通过如下方式禁用_field_names字段:
    PUT tweets
    {
      "mappings": {
        "_doc": {
          "_field_names": {
            "enabled": false
          }
        }
      }
    }
    
    1. _ignored
      设置为ignore_malformed=true的所有字段。
    • routing meta-field
    1. _routing
      分片路由字段。
    • other meta-field
      1._meta
      用于用户自定义的元数据,例如:
    PUT my_index
    {
      "mappings": {
        "_doc": {
          "_meta": { 
            "class": "MyApp::User",
            "version": {
              "min": "1.0",
              "max": "1.3"
            }
          }
        }
      }
    }
    

    本文初步介绍了Elasticsearch 类型映射与元字段类型,后续文章将介绍映射参数、elasticsearch支持的数据类型、自动类型映射机制等。


    见文如面,我是威哥,热衷于成体系剖析JAVA主流中间件,关注公众号『中间件兴趣圈』,回复专栏可获取成体系专栏导航,回复资料可以获取笔者的学习思维导图。
    在这里插入图片描述

    展开全文
  • 映射类型:字典

    千次阅读 2018-01-02 14:58:42
    字典是一种通过名字引用值的数据结构,字典中的值并没有特殊的顺序,但是都是存储在一个特定的键(Key)里,键可以是数字、字符串或者元组。 1.如何创建字典和给字典赋值 创建字典只需要把字典赋值给一个变量,...
  • Python3入门之——映射类型

    千次阅读 2020-08-31 23:20:02
    映射是键值数据项的组合
  • 1、修改类型映射关系 在项目中,为了降低数据的存储空间,status状态字段一般使用tinyint, 1个tinyint型数据只占用个字节,个int型数据占用四个字节。这看起来似乎差别不大,但是在比较大的表中,字节数的...
  • Hibernate映射类型 Java类型 标准SQL类型 字节大小 integer/int java.lang.Integer/int INTEGER 4Byte long java.lang.Long/long BIGINT 8Byte short java.lang.Short/short SMALLINT...
  • 文章目录定义示例使用总结 ...#给example索引新增个birthday字段,类型为date, 格式可以是yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss #添加日期类型映射 PUT test_label_supplier/docs/_mapping { "properties":...
  • TypeScript实战-18-TS高级类型-映射类型

    千次阅读 2019-09-20 18:56:14
    本篇介绍TS的另个高级类型-映射类型 二,映射类型 映射类型: TS允许将个类型映射成另外个类型 将个接口的所有属性映射为只读: // 定义接口Obj interface Obj { a: number b: string c: boolean } // ...
  • MyBatis面试题(2020最新版)

    万次阅读 多人点赞 2019-09-24 16:40:33
    整理好的MyBatis面试题库,史上最全的MyBatis面试题,MyBatis面试宝典,特此分享给大家 MyBatis 介绍 MyBatis 是款优秀的...MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plai...
  • TypeScript的映射类型

    千次阅读 2017-10-27 14:39:00
    映射类型 个常见的任务是将个已知的类型每个属性都变为可选的: interface PersonPartial { name?: string; age?: number; } 或者我们想要个只读版本: interface PersonReadonly { readonly name: ...
  • 从本小节开始我们开始学习es中常用的元数据类型和字段映射,学习和理解它们可以有助于理解es及其工作机制。 其主要分为两大类。 其,元字段,元字段用于ES对每个文档自带的元数据结构,包括 _index,_type, _id...
  • 方式:使用自动映射处理一映射 实体类改造 UserMapper接口增加接口方法 UserMapper.xml增加SQL 单元测试 方式二:使用resultMap配置一映射 UserMapper接口增加接口方法 UserMapper.xml增加SQL 单元测试 ...
  • Mybatis之输入输出映射(共三种类型)

    千次阅读 2018-12-31 17:38:12
    、输入parameterType输出resultType类型(resultType:列名和pojo中的属性名要一致) Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称,其中,#{}:占位符号,相对于?,${}:sql拼接...
  • java和mysql 的数据类型对照(映射)表 数据类型: java mysql byte tinyint short smallint int int(★) long bigint char / String varchar(★) / char boolean tinyint / int 代替 float / ...
  • 下面我来学习es中另外一种重要的字符串类型keyword。 一、概述 关键字。关键字是个精准值,通常用于过滤、排序、参与聚合等。关键字不参与分词。 二、使用 上边介绍的text文本字段在映射时要设置分词器,keyword字段...
  • 华中科技大学计算机组成原理慕课答案

    万次阅读 多人点赞 2020-01-26 00:09:18
    、单项选择题 1、下列说法中,错误的是( B ) A.固件功能类似软件,形态类似硬件 B.寄存器的数据位对微程序级用户透明 C.软件与硬件具有逻辑功能的等效性 D.计算机系统层次结构中,微程序属于硬件级 2、...
  • ES学习之单个索引映射多个类型

    万次阅读 2018-06-19 13:31:00
    在ES6.0.0及更高的版本中,创建的索引只能包含映射类型。在6.0.0以下的版本中创建的个索引映射多个类型的索引在6.0.0版本中继续发挥作用,但是将在7.0.0中完全删除。 自第次发布弹出式搜索以来,每个文档都...
  • jpa字段类型映射说明

    千次阅读 2018-09-28 10:16:08
    它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据  JPA规范要求在类路径的META-INF目录下放置persistence.xml  JPA 中将一个类注解成实体类(entity class)有两种不同的注解方式:基于属性...
  • PostgreSQL数据库允许你使用如下的语法创建枚举类型: CREATE TYPE animal_type AS ENUM('DOG', 'CAT', 'SQUIRREL'); 创建以后就可以使用animal_type作为数据表中的数据类型,例如: create table pet ( ...
  • Hibernate之两种一关系映射方式

    千次阅读 2018-01-15 21:39:22
    前言在前面的Hibernate学习中已经介绍了多对一、一对多、多对多...一种是基于外键的映射关系。一种是基于主键的映射关系。本文将分别从具体案例出发,介绍两种不同的一对一映射配置。案例说明:需求 一个用户对应一个
  • ## 记录次 curl -XPOST localhost:8305/_aliases -d ' { &amp;amp;amp;amp;amp;quot;actions&amp;amp;amp;amp;amp;quot;: [ { &amp;amp;amp;amp;amp;quot;remove&amp;amp;amp;amp;amp;quot;...
  • 基本映射是对个实体进行映射,关联映射就是处理多个实体之间的关系,将关联关系映射到数据库中,所谓的关联关系在对象模型中有个或多个引用。
  • Elasticsearch的映射用来定义个索引中的文档如何被存储,定义映射类似于定义个Mongo DB集合,在Elasticsearch 7.x中,映射和索引是的关系。映射分为静态映射和动态映射,前者需要用户手动定义,后者则...
  • 当我们在调用个Java native方法的时候,方法中的参数是如何传递给C/C++本地函数中的呢?Java方法中的参数与C/C++函数中的参数,它们之间是怎么转换的呢?我猜你应该也有相关的疑虑吧,咱们先来看个例子,还是以...
  • 映射定义索引中有什么字段、字段的类型等结构信息。相当于数据库中表结构定义,或 solr中的schema。因为lucene索引文档时需要知道该如何来索引存储文档的字段。 ES中支持手动定义映射,动态映射方式。 Create ...
  • 它是一种总称的数据类型。 一、标量 标量(scalar),也就是一个单独的字符串(sting)或数字(numbers)。比如“北京”这个单独的词。 二、序列 序列(sequence),也就是若干个相关的数据按照一定顺序并列在...
  • JPA

    千次阅读 多人点赞 2019-01-05 09:43:11
    今天做东西的时候使用到了JPA,在这里把JPA需要注意的知道的体系结构,给大家罗列遍。如果能帮到大家一点,希望大家,点个赞关注一下,后期还会更新更多技术。 、JPA概述  1.使用JPA持久化对象的步骤 创建 ...
  • 在Elasticsearch6.0.0或更新的版本中创建的索引可能只包含个单一的映射类型。 在Elasticsearch5.x中创建的多映射类型的索引在Elasticsearch6.x中将如以前一样可用。 映射类型将在Elasticsearch7.0.0被彻底移除。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 687,910
精华内容 275,164
关键字:

列表是一种映射类型