Effective Python列表和字典(2.1):列表切片、解包以及sort函数用法

231 阅读4分钟

本篇文章汇总了 Python 当中列表的高效用法,主要包括:对列表进行切片、通过*操作符对列表进行解包、通过key参数制定sort函数的排序方法。

1. 对列表进行切片

切片是Python中的一个强大的特性,可以用来获取序列的子序列。 使用切片的建议: 1. 从头或尾开始切片时,不要使用 0 或- 1 作为索引,直接使用空值即可。 2. 切片允许起始位置和结束位置越界,不会报错,所以不用担心切片是否真有这么多元素。 3. 可以使用赋值运算符给切片赋值,但可能会改变原列表的长度。

a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
print('First four:', a[:4])   # 从起始到第4个元素,不包括a[4]
print('Last four:', a[-4:])   # 从倒数第4个元素到最后
print('Middle two:', a[3:5])  # 元素:a[3], a[4]
print('All elements:', a[:20])  # 所有元素。尽管列表a的个数小于20个,但是不会报错

# 切片的赋值。切片可以被赋值
# 如果赋值运算符的右侧个数与切片的长度不同,切片的长度会改变
a[2:7] = [99, 22, 14]
print(a)   # ['a', 'b', 99, 22, 14, 'h']
# 切片赋值也可以删除元素
a[2:3] = [11, 12, 13]
print(a)   # ['a', 'b', 11, 12, 13, 22, 14, 'h']

# 起止位置都为空,相当于复制整个列表
b = a[:]
assert b == a and b is not a

2. 使用 * 对列表进行解包操作

为了将一个列表分成几部分,通常的做法是使用下标和切片操作符,但是这种方法很容易出错。 当需要把一个列表顺序地分为几部分时(例如,取出前两个元素以及剩余的元素),可以使用 * 操作符来接收多余的元素。 这种带星号的表达式可以出现赋值运算符左侧的任意位置,它总是会形成一份含有零个或多个值的列表。需要注意的是,带星号的表达式只能出现一次。

def generate_csv():
   yield ('Date', 'Make', 'Model', 'Year', 'Price')
   yield ('2020-01-01', 'Tesla', 'Model S', '2019', 79999)
   yield ('2025-01-02', 'Tesla', 'Model L', '2019', 99999)

def main():
   it = generate_csv()
   header, *rows = it
   print('CSV Header:', header)
   print('CSV Rows:', rows)
   print('Row count:', len(rows))
   
if __name__ == '__main__':
   main()

输出:

CSV Header: ('Date', 'Make', 'Model', 'Year', 'Price')
CSV Rows: [('2020-01-01', 'Tesla', 'Model S', '2019', 79999), ('2025-01-02', 'Tesla', 'Model L', '2019', 99999)]
Row count: 2

3. 通过 key 关键字参数给 sort 函数制定排序方法

内置的列表类型提供了名为 sort 方法,可以根据多项指标给 list 实例中的元素排序。默认情况下,sort 方法总是按照自然升序排列列表内的元素。例如,对于整数,自然升序是从小到大;对于字符串,自然升序是按照字母表顺序。

凡是具备自然顺序的内置类型几乎都可以使用 sort 方法排序,例如整数、浮点数、字符串等。

但是,对于自定义类型,必须给 sort 方法的 key 参数提供一个排序函数,以便告诉Python如何对自定义类型的实例进行排序。

如果排序时多个指标之间有优先级,可以把它们放在一个元组当中,让 key 返回这样的元组。对于支持一元减操作符的类型来说,可以单独给这项指标取反,让排序算法在这项指标上按照相反的方向处理。

如果这些指标不支持一元减操作符,可以多次调用 sort 方法,并在每次调用时分别指定 key 函数与 reverse 参数。最次要的指标放在第一轮处理,然后逐步处理更为重要的指标,首要指标放在最后一轮处理。

def sort_nums(numbers):
    return numbers.sort()

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

def sort_tools_by_name(tools):
    tools.sort(key=lambda x: x.name)

def sort_tools_by_weight(tools):
    tools.sort(key=lambda x: x.weight)

def sort_tools_by_weight_name(tools):
    tools.sort(key=lambda x: (x.weight, x.name))

def sort_tools_by_reverse_weight_name(tools):
    tools.sort(key=lambda x: (-x.weight, x.name))

def sort_tools_by_reverse_name_weight(tools):
    tools.sort(key=lambda x: x.weight)
    tools.sort(key=lambda x: x.name, reverse=True)

def main():
    nums = [3, 5, 1, 4, 2]
    print('Unsorted numbers:', nums)
    sort_nums(nums)
    print('Sorted numbers:', nums)
    print()
    
    tools = [
        Tool('hammer', 3.5),
        Tool('screwdriver', 0.5),
        Tool('chisel', 1.25),
        Tool('file', 0.75),
        Tool('saw', 0.5),
    ]
    print('Unsorted:', repr(tools))
    # Unsorted: [Tool('hammer', 3.5), Tool('screwdriver', 0.5), Tool('chisel', 1.25), Tool('file', 0.75), Tool('saw', 0.5)]
    print()
    
    sort_tools_by_name(tools)
    print('Sorted by name:', tools)
    # Sorted by name: [Tool('chisel', 1.25), Tool('file', 0.75), Tool('hammer', 3.5), Tool('saw', 0.5), Tool('screwdriver', 0.5)]
    print()
    
    sort_tools_by_weight(tools)
    print('Sorted by weight:', tools)
    # Sorted by weight: [Tool('saw', 0.5), Tool('screwdriver', 0.5), Tool('file', 0.75), Tool('chisel', 1.25), Tool('hammer', 3.5)]
    print()
    
    sort_tools_by_weight_name(tools)
    print('Sorted by weight, name:', tools)
    # Sorted by weight, name: [Tool('saw', 0.5), Tool('screwdriver', 0.5), Tool('file', 0.75), Tool('chisel', 1.25), Tool('hammer', 3.5)]
    print()
    
    sort_tools_by_reverse_weight_name(tools)
    print('Sorted by weight in reverse, name:', tools)
    # Sorted by weight in reverse, name: [Tool('hammer', 3.5), Tool('chisel', 1.25), Tool('file', 0.75), Tool('saw', 0.5), Tool('screwdriver', 0.5)]
    print()
    
    sort_tools_by_reverse_name_weight(tools)
    print('Sorted by name in reverse, weight:', tools)
    # Sorted by name in reverse, weight: [Tool('screwdriver', 0.5), Tool('saw', 0.5), Tool('hammer', 3.5), Tool('file', 0.75), Tool('chisel', 1.25)]
    print()
    
if __name__ == '__main__':
    main()