Python数据类型之字典

in 互联网技术 with 0 comment  访问: 2,789 次

在Python中字典(dict)是一种key value的数据类型,使用就像我们上学用的字典,通过笔划、字母来查对应页的详细内容,同时在所有数据类型中使用频率也是相当高的,而且它的访问方式是通过键来获取到对应的值,属于可变类型,其中字典的Key必须是不可变类型,比如字符串、数字、元组都可以作为字典的Key,但是Value可以是任何对象。

字典是Python中最优秀的特性之一,许多高效、优雅的算法即以此为基础。

那这里总结一下字典的特征:

  1. 字典是序列类型,但是是无序序列,所以没有分片和索引;
  2. 字典中的数据每个都有键值对组成,即KV对;
  3. Key必须是可哈希的值,比如int,string,float,tuple, 但是,list,set,dict 不行;
  4. Value任何值均可

字典的增删改查

1.字典的创建:
1.1 常规方法:

>>> personal_file = {'job': 'iter', 'age': 18, 'hometown': 'NanChang'}
>>> type(personal_file)
<type 'dict'>
>>> print(personal_file)
{'hometown': 'NanChang', 'job': 'iter', 'age': 18}

1.2 fromkeys方法:
Python字典fromkeys()函数用于创建一个新字典,以序列seq中元素做字典的键,value为字典所有键对应的初始值。

fromkeys()方法语法:

dict.fromkeys(seq[, value])

seq --> 字典键值列表
value --> 可选参数, 设置键序列(seq)的值。

>>> name_list = ['Tom', 'Jim', 'Nock']
>>> personal_file = dict.fromkeys(name_list, 10)
>>> print(personal_file)
{'Jim': 10, 'Nock': 10, 'Tom': 10}
>>> personal_file = dict.fromkeys(name_list, (10,9,8))
>>> print(personal_file)
{'Jim': (10, 9, 8), 'Nock': (10, 9, 8), 'Tom': (10, 9, 8)}
>>> personal_file = dict.fromkeys(name_list)
>>> print(personal_file)
{'Jim': None, 'Nock': None, 'Tom': None}

# 创建的personal_file的value值指向同一块内存空间,这就有些类似浅拷贝了

fromkeys也就是不给初值时默认为None,给初值的话为所有键的值为初值。

更多组合其他函数使用创建请阅读: https://fashengba.com/post/python-create-dict-method.html

2. 字典的访问:

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> name_info['Nock']
18
>>> name_info['Nocks']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Nocks'

# 如果字典里面不存在某个'key',获取就会报KeyError的错误信息

>>> name_info.get('Nock')
18
>>> name_info.get('Nocks')
>>> print(name_info.get('Nocks'))
None
>>> name_info.get('Nocks','default_custome')
'default_custome'

# .get 方法比较友好,如果不存在的'key'默认返回None,但是你可以设置默认值get(key, default=)

如果要100%确认字典拥有的key,才去获取他的值,那应该怎么做呢,参考:https://fashengba.com/post/python-determines-key-in-dict.html,利用in关键字即可:

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> if 'Nocks' in name_info:
...     print(name_info['nocks'])
... else:
...     print('dict not key "Nocks"!')
... 
dict not key "Nocks"!


>>> if 'Jim' in name_info: name_info['Jim']
... 
20

3. 字典的添加:

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> name_info['Cat'] = 21
>>> name_info
{'Tom': 21, 'Cat': 21, 'Jim': 20, 'Nock': 18}

# 不存在才添加,存在就是修改了

update字典添加到字典里面:

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> add_name = {'lucky': 19, 'Jerry': 30}
>>> name_info.update(add_name)
>>> print(name_info)
{'Tom': 21, 'Jerry': 30, 'Jim': 20, 'lucky': 19, 'Nock': 18}

4. 字典的修改:

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> name_info['Jim'] = 30
>>> name_info
{'Tom': 21, 'Jim': 30, 'Nock': 18}

5. 字典的删除:

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> name_info.pop('Jim')  # 标准删除,有返回值
20
>>> name_info
{'Tom': 21, 'Nock': 18}
>>> del name_info['Tom']  # del方法删除,无返回
>>> name_info
{'Nock': 18}

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> name_info.popitem()  # 随机删除,返回元组
('Tom', 21)
>>> name_info.popitem()
('Jim', 20)
>>> name_info
{'Nock': 18}

清空字典:

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> del name_info   # 从内存中抹掉
>>> name_info
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'name_info' is not defined

>>> name_info = {'Jim': 20, 'Nock': 18, 'Tom': 21}
>>> name_info.clear()  # 清空字典里面数据,变为空字典
>>> name_info
{}

字典其他方法

class dict(object):
    """
    dict() -> new empty dictionary
    dict(mapping) -> new dictionary initialized from a mapping object's
        (key, value) pairs
    dict(iterable) -> new dictionary initialized as if via:
        d = {}
        for k, v in iterable:
            d[k] = v
    dict(**kwargs) -> new dictionary initialized with the name=value pairs
        in the keyword argument list.  For example:  dict(one=1, two=2)
    """

    def clear(self): # real signature unknown; restored from __doc__
        """ 清除内容 """
        """ D.clear() -> None.  Remove all items from D. """
        pass

    def copy(self): # real signature unknown; restored from __doc__
        """ 浅拷贝 """
        """ D.copy() -> a shallow copy of D """
        pass

    @staticmethod # known case
    def fromkeys(S, v=None): # real signature unknown; restored from __doc__
        """
        dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
        v defaults to None.
        """
        pass

    def get(self, k, d=None): # real signature unknown; restored from __doc__
        """ 根据key获取值,d是默认值 """
        """ D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None. """
        pass

    def has_key(self, k): # real signature unknown; restored from __doc__
        """ 是否有key """
        """ D.has_key(k) -> True if D has a key k, else False """
        return False

    def items(self): # real signature unknown; restored from __doc__
        """ 所有项的列表形式 """
        """ D.items() -> list of D's (key, value) pairs, as 2-tuples """
        return []

    def iteritems(self): # real signature unknown; restored from __doc__
        """ 项可迭代 """
        """ D.iteritems() -> an iterator over the (key, value) items of D """
        pass

    def iterkeys(self): # real signature unknown; restored from __doc__
        """ key可迭代 """
        """ D.iterkeys() -> an iterator over the keys of D """
        pass

    def itervalues(self): # real signature unknown; restored from __doc__
        """ value可迭代 """
        """ D.itervalues() -> an iterator over the values of D """
        pass

    def keys(self): # real signature unknown; restored from __doc__
        """ 所有的key列表 """
        """ D.keys() -> list of D's keys """
        return []

    def pop(self, k, d=None): # real signature unknown; restored from __doc__
        """ 获取并在字典中移除 """
        """
        D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
        If key is not found, d is returned if given, otherwise KeyError is raised
        """
        pass

    def popitem(self): # real signature unknown; restored from __doc__
        """ 获取并在字典中移除 """
        """
        D.popitem() -> (k, v), remove and return some (key, value) pair as a
        2-tuple; but raise KeyError if D is empty.
        """
        pass

    def setdefault(self, k, d=None): # real signature unknown; restored from __doc__
        """ 如果key不存在,则创建,如果存在,则返回已存在的值且不修改 """
        """ D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D """
        pass

    def update(self, E=None, **F): # known special case of dict.update
        """ 更新
            {'name':'alex', 'age': 18000}
            [('name','sbsbsb'),]
        """
        """
        D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
        If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
        If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
        In either case, this is followed by: for k in F: D[k] = F[k]
        """
        pass

    def values(self): # real signature unknown; restored from __doc__
        """ 所有的值 """
        """ D.values() -> list of D's values """
        return []

    def viewitems(self): # real signature unknown; restored from __doc__
        """ 所有项,只是将内容保存至view对象中 """
        """ D.viewitems() -> a set-like object providing a view on D's items """
        pass

    def viewkeys(self): # real signature unknown; restored from __doc__
        """ D.viewkeys() -> a set-like object providing a view on D's keys """
        pass

    def viewvalues(self): # real signature unknown; restored from __doc__
        """ D.viewvalues() -> an object providing a view on D's values """
        pass

    def __cmp__(self, y): # real signature unknown; restored from __doc__
        """ x.__cmp__(y) <==> cmp(x,y) """
        pass

    def __contains__(self, k): # real signature unknown; restored from __doc__
        """ D.__contains__(k) -> True if D has a key k, else False """
        return False

    def __delitem__(self, y): # real signature unknown; restored from __doc__
        """ x.__delitem__(y) <==> del x[y] """
        pass

    def __eq__(self, y): # real signature unknown; restored from __doc__
        """ x.__eq__(y) <==> x==y """
        pass

    def __getattribute__(self, name): # real signature unknown; restored from __doc__
        """ x.__getattribute__('name') <==> x.name """
        pass

    def __getitem__(self, y): # real signature unknown; restored from __doc__
        """ x.__getitem__(y) <==> x[y] """
        pass

    def __ge__(self, y): # real signature unknown; restored from __doc__
        """ x.__ge__(y) <==> x>=y """
        pass

    def __gt__(self, y): # real signature unknown; restored from __doc__
        """ x.__gt__(y) <==> x>y """
        pass

    def __init__(self, seq=None, **kwargs): # known special case of dict.__init__
        """
        dict() -> new empty dictionary
        dict(mapping) -> new dictionary initialized from a mapping object's
            (key, value) pairs
        dict(iterable) -> new dictionary initialized as if via:
            d = {}
            for k, v in iterable:
                d[k] = v
        dict(**kwargs) -> new dictionary initialized with the name=value pairs
            in the keyword argument list.  For example:  dict(one=1, two=2)
        # (copied from class doc)
        """
        pass

    def __iter__(self): # real signature unknown; restored from __doc__
        """ x.__iter__() <==> iter(x) """
        pass

    def __len__(self): # real signature unknown; restored from __doc__
        """ x.__len__() <==> len(x) """
        pass

    def __le__(self, y): # real signature unknown; restored from __doc__
        """ x.__le__(y) <==> x<=y """
        pass

    def __lt__(self, y): # real signature unknown; restored from __doc__
        """ x.__lt__(y) <==> x<y """
        pass

    @staticmethod # known case of __new__
    def __new__(S, *more): # real signature unknown; restored from __doc__
        """ T.__new__(S, ...) -> a new object with type S, a subtype of T """
        pass

    def __ne__(self, y): # real signature unknown; restored from __doc__
        """ x.__ne__(y) <==> x!=y """
        pass

    def __repr__(self): # real signature unknown; restored from __doc__
        """ x.__repr__() <==> repr(x) """
        pass

    def __setitem__(self, i, y): # real signature unknown; restored from __doc__
        """ x.__setitem__(i, y) <==> x[i]=y """
        pass

    def __sizeof__(self): # real signature unknown; restored from __doc__
        """ D.__sizeof__() -> size of D in memory, in bytes """
        pass

    __hash__ = None

字典嵌透

# 在列表中嵌透字典
to_do_list = [
    {'name': 'Tom', 'age': 20, 'job': 'dev'},
    {'name': 'nock', 'age': 18, 'job': 'devops'}
]

# 字典中嵌透列表和字典, Example: Zabbix Discovery
discovery_data = {
    "data": [
        {
            "{#CONSUMER_GROUP}": "JavaConsumer",
            "{#TOPIC_NAME}": "javaAgentTopic",
            "{#PARTITION_NUM}": "0"
        },
        {
            "{#CONSUMER_GROUP}": "HostConsumer",
            "{#TOPIC_NAME}": "hostAgentTopic",
            "{#PARTITION_NUM}": "0"
        }
    ]
}

字典的遍历

name_info = {'Jim': 20, 'Nock': 18, 'Tom': 20, 'Jerry': 25}

# 键值 会先把dict转成list,数据里大时莫用
for k, v in name_info.items():
    print('Dict name_info key is: %s, value is: %s' % (k, v))


# 按照Key循环 sorted按照key排序
for k in name_info.keys():
    print(k)

for k in name_info:
    print(k)

for k in sorted(name_info.keys()):
    print(k)

# 按照Value循环 set去重
for v in name_info.values():
    print(v)

for v in set(name_info.values()):
    print(v)

字典几种高阶使用场景

1. 字典作为计数器

假设给你一个字符串,你想计算每个字母出现的次数。使用字典的实现有一个优势,即我们不需要事先知道字符串中有几种字母, 只要在出现新字母时分配空间就好了。

def histogram(strings):
    string_dict = dict()
    for letter in strings:
        string_dict[letter] = string_dict.get(letter, 0) + 1

    return string_dict

测试:

print(histogram('apple'))

{'e': 1, 'l': 1, 'a': 1, 'p': 2}

设置一个直方图函数,利用字典的get方法,如果能够获取到则计数+1,如果没有,则就默认返回0+1计数。

2. 字典逆向查找

给定一个字典words以及一个键a,很容易找到相应的值 word_num = words['a'] 。 该运算被称作查找(lookup)。

但是如果你想通过word_num找到'a'呢? 有两个问题:第一,可能有不止一个的键其映射到值word_num。 你可能可以找到唯一一个,不然就得用list把所有的键包起来。 第二,没有简单的语法可以完成 逆向查找(reverse lookup),你必须搜索。

下面这个函数接受一个值并返回映射到该值的第一个键:

def reverse_lookup(input_dict, find_value):
    for dict_key in input_dict:
        if input_dict[dict_key] == find_value:
            return dict_key

    raise LookupError('You find value %s does not appear in the dictionary' % find_value)

word_dict = {'a': 2, 'w': 1, 'r': 3, 'k': 1}

print(reverse_lookup(word_dict, 4))

逆向查找比正向查找慢得多,如果你频繁执行这个操作或是字典很大,程序性能会变差。

WeZan