Python 小贴士(2)列表与字典

11. 对序列做切片

python 中有一种写法,可以从序列里面切割出一部分内容,获取原序列的某个子集合。可以切割内置的 list、str 和 bytes。凡是实现了 __getitem__ 和 __setitem__ 的类都可以切割。

>>> a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> print('Middle Two: ', a[3:5])
Middle Two:  ['d', 'e']
>>> print('All but ends: ', a[1:7])
All but ends:  ['b', 'c', 'd', 'e', 'f', 'g']

如果是从头开始切割列表,应该省略冒号左边的下标 0 ,如果是一直取到列表末尾,应该省略冒号右侧的下标。用负数做下标,表示从列表末尾往前算:

>>> a[:]
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> a[:5]
['a', 'b', 'c', 'd', 'e']
>>> a[:-1]
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> a[4:]
['e', 'f', 'g', 'h']
>>> a[-3:]
['f', 'g', 'h']
>>> a[2:5]
['c', 'd', 'e']
>>> a[2:-1]
['c', 'd', 'e', 'f', 'g']
>>> a[-3:-1]
['f', 'g']

切割出来的列表是一份全新的列表,即使把某个元素换掉,也不会影响原列表中的相应位置。

>>> b = a[3:]
>>> print('Before: ', b)
Before:  ['d', 'e', 'f', 'g', 'h']
>>> b[1] = 99
>>> print('After: ', b)
After:  ['d', 99, 'f', 'g', 'h']
>>> print('No change: ', a)
No change:  ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

切片可以出现在赋值符号的左侧,表示用右侧的元素把原列表中位于这个范围之内的元素换掉。

>>> print('Before: ', a)
Before:  ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> a[2:7] = [99, 22, 14]
>>> print('After: ', a)
After:  ['a', 'b', 99, 22, 14, 'h']
>>> a[2:3] = [47, 11]
>>> print('After: ', a)
After:  ['a', 'b', 47, 11, 22, 14, 'h']

起止位置都为空的切片如果出现在赋值符号右侧,表示给这个列表做副本,这样制作出来的新列表内容和原列表相同,但 id 不同。

>>> b = a[:]
>>> b == a
True
>>> b is a
False

12. 不要在切片里同时指定起止下标和步进

切片还有一种写法是 somelist[start:end:stride],可以很容易把奇数位置上的元素与偶数位置上的元素分别选取出来:

>>> x = [1, 2, 3, 4, 5, 6]
>>> odds = x[::2]
>>> evens = x[1::2]
>>> print(odds)
[1, 3, 5]
>>> print(evens)
[2, 4, 6]

逆序:

>>> x = b'kubernetes'
>>> y = x[::-1]
>>> print(y)
b'setenrebuk'
>>> x = '冰棒'
>>> y = x[::-1]
>>> print(y)
棒冰

UTF-8 字节数据无法逆序:

>>> w = '冰棒'
>>> x = w.encode('utf-8')
>>> y = x[::-1]
>>> z = y.decode('utf-8')
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    z = y.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x92 in position 0: invalid start byte

其他举例:

>>> x = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> x[::2]
['a', 'c', 'e', 'g']
>>> x[::-2]
['h', 'f', 'd', 'b']
>>> x[2::2]
['c', 'e', 'g']
>>> x[-2::-2]
['g', 'e', 'c', 'a']
>>> x[-2:2:-2]
['g', 'e']
>>> x[2:2:-2]
[]

建议不要把起止下标和步进值同时写在切片里,如果必须指定步进,尽量使用正数,而且起止下标都要留空。也可以分两步来做(一次隔位选取,一次做切割)。也可以用 itertools.isslice 方法。

13. 通过带星号的拆分操作捕获多个元素,不用切片

>>> car_ages = [0, 9, 4, 8, 7, 20, 19, 1, 6, 15]
>>> car_ages_descending = sorted(car_ages, reverse=True)
>>> oldest, second_oldest, *others = car_ages_descending
>>> print(oldest, second_oldest, others)
20 19 [15, 9, 8, 7, 6, 4, 1, 0]

在使用这种写法时,至少要有一个普通的接受变量与它搭配。对于单层结构来说,同一级里面最多出现一次带星号的拆分。

14. 用 sort 方法的 key 参数来表示复杂的排序逻辑

class Tool:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight
    
    def __repr__(self):
        return f'Tool({self.name!r}, {self.weight})'

tools = [
    Tool('level', 3.5),
    Tool('hammer', 1.25),
    Tool('screwdriver', 0.5),
    Tool('chisel', 0.25),
]

print('Unsorted:', repr(tools))
tools.sort(key=lambda x: x.name)
print('\nSorted: ', tools)
>>>
Unsorted:  [Tool('level',       3.5),
            Tool('hammer',      1.25),
            Tool('screwdriver', 0.5),
            Tool('chisel',      0.25)]
Sorted:    [Tool('chisel',      0.25),
            Tool('hammer',      1.25),
            Tool('level',       3.5),
            Tool('screwdriver', 0.5)]

 15. 不要过分依赖给字典添加条目时所用的顺序

从 Python 3.6 开始,字典会保留键值对在添加时的所用的顺序,而且 Python 3.7 版的语言规范正式确立了这条规则。而在以前的版本中,字典类型是用哈希表算法来实现的(这个算法通过内置的 hash 函数与一个随机的种子数来运行,该种子数会在每次启动 Python 解释器时确定)。这样的机制导致这些键值对在字典中的存放顺序不一定会与添加时的顺序相同。

16. 用 get 处理键不在字典中的情况,不要使用 in 与 KeyError

>>> counters = {
	'pumpernickel': 2,
	'sourdough': 1,
	}
>>> key = 'wheat'
>>> count = counters.get(key, 0)
>>> counters[key] = count + 1
>>> counters
{'pumpernickel': 2, 'sourdough': 1, 'wheat': 1}

如果字典里保存的数据比较复杂,比如列表。

>>> votes = {
	'baguette': ['Bob', 'Alice'],
	'ciabatta': ['Coco', 'Deb'],
	}
>>> key = 'brioche'
>>> who = 'Elmer'
>>> names = votes.get(key)
>>> if names is None:
	votes[key] = names = []

	
>>> names.append(who)
>>> votes
{'baguette': ['Bob', 'Alice'], 'ciabatta': ['Coco', 'Deb'], 'brioche': ['Elmer']}

在 3.8 或更新的版本中可以使用赋值表达式,进一步简化代码:

>>> if (names := votes.get(key)) is None:
	votes[key] = names = []

	
>>> names.append(who)

17. 用 defaultdict 处理内部状态中缺失的元素,不要用 setdefault

如果你管理的字典可能需要添加任意的键,那么应该考虑能否用内置的 collections 模块中的 defaultdict 实例来解决问题。

from collections import defaultdict

class Visits:
    def __init__(self):
        self.data = defaultdict(set)

    def add(self, country, city):
        self.data[country].add(city)

visits = Visits()
visits.add('England', 'Bath')
visits.add('England', 'London')
print(visits.data)

>>>
defaultdict(<class 'set'>, {'England': {'London', 'Bath'}})

18. 利用 __missing__ 构造依赖键的默认值

from collections import defaultdict

def open_picture(profile_path):
    try:
        return open(profile_path, 'a+b')
    except OSError:
        print(f'Failed to open path {profile_path}')
        raise

class Pictures(dict):
    def __missing__(self, key):
        value = open_picture(key)
        self[key] = value
        return value

pictures = Pictures()
handle = pictures[path]
handle.seek(0)
image_data = handle.read()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在Python中,列表字典是两种常用的数据结构。列表是有序的可变序列,可以存储多个元素,每个元素可以是不同的数据类型。可以使用len()函数来获取列表的长度,该函数返回列表中元素的个数。例如,对于一个列表fc={'lily':5,'lucy':9},可以使用len(fc)来获取列表fc的长度,结果为2。\[1\] 字典是一种无序的可变容器,由键值对组成。每个键值对都是一个键和一个对应的值。可以使用len()函数来获取字典的长度,该函数返回字典中键值对的个数。另外,可以使用values()方法来获取字典的所有值,它返回一个包含字典所有值的列表的视图对象。例如,对于一个字典dict_data = {1: 1, 2: 2, 3: 4},可以使用dict_data.values()来获取字典dict_data的所有值,结果为dict_values(\[1, 2, 4\])。\[2\] 在Python中,可以使用update()方法将一个字典中的键值对添加到另一个字典中。该方法接受一个字典作为参数,将该字典中的键值对添加到当前字典中。如果两个字典中存在相同的键,则更新当前字典中的值。例如,对于两个字典dict_data1 = {1: 1, 2: 2}和dict_data2 = {1: 4, 4: 5},可以使用dict_data1.update(dict_data2)将字典dict_data2中的键值对添加到字典dict_data1中,结果为{1: 4, 2: 2, 4: 5}。\[3\] 总结来说,列表是有序的可变序列,可以使用len()函数获取列表的长度。字典是无序的键值对容器,可以使用len()函数获取字典的长度,使用values()方法获取字典的所有值,使用update()方法将一个字典中的键值对添加到另一个字典中。 #### 引用[.reference_title] - *1* [python列表字典](https://blog.csdn.net/eric3012/article/details/119960458)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [python列表字典使用(详细)](https://blog.csdn.net/Fran_klin__/article/details/125145194)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值