个性化阅读
专注于IT技术分析

Python列表深入理解教程

本文概述

在进行数据科学时, 你可能会发现自己想要阅读列表列表, 过滤列名称, 从列表中删除元音或展平矩阵。你可以轻松使用lambda函数或for循环;众所周知, 有多种方法可以解决此问题。另一种方法是使用列表推导。

本教程将讨论最后一个主题:

  • 首先, 你将简要回顾一下什么是Python列表以及它们与其他Python数据结构的比较方式;
  • 接下来, 你将深入研究Python列表推导:你将了解有关Python列表推论的更多信息, 如何构造列表推导, 如何将其作为循环或lambda函数进行重写, ….仅阅读有关此内容的内容, 但你还将做一些练习!
  • 掌握基础知识之后, 还可以通过向其添加条件来微调列表理解:你将学习如何在列表理解中包含条件, 以及如何处理多个if条件和if-else语句。
  • 最后, 你将深入了解嵌套列表理解, 以对列表进行多次迭代。

如果你还对与迭代器和生成器一起处理列表推导感兴趣?查看srcmini的Python数据科学工具箱课程!

python列表理解

Python列表

到现在为止, 你可能已经开始使用具有几种数据类型的值了。你已将每个值保存在单独的变量中:每个变量代表一个值。但是, 在数据科学中, 你将经常使用许多数据点, 这将使得很难继续将每个值存储在单独的变量中。而是将所有这些值存储在Python列表中。

列表是Python中的四个内置数据结构之一。你可能知道的其他数据结构是元组, 字典和集合。从某种意义上说, Python是一种复合数据类型, 因此Python中的列表不同于int或bool:你可以将值分组在一起。实际上, 这些值不必是同一类型:它们可以是布尔值, 字符串, 整数, …值的组合。

这里要注意的重要一点是, 列表是项目或对象的有序集合。这使Python中的列表成为”序列类型”, 因为它们的行为就像一个序列。这意味着它们可以被迭代。序列的其他示例是字符串, 元组或集合。

提示:如果你想了解更多, 测试或练习Python列表知识, 可以通过阅读此处Python列表上最常见的问题来做到。

现在, 请注意:你将建立一个带有两个方括号的列表;在这些括号内, 你将使用逗号分隔值。然后, 你可以将列表分配给变量。你放入Python列表中的值可以是任何数据类型, 甚至可以是列表!

看下面的列表示例:

提示:在上述srcmini Light块中包含的IPython Shell中构建你自己的列表!

Python列表理解

回顾一下Python列表的摘要, 你可以轻松地看到在Python中定义和创建列表可能是一项繁琐的工作:分别输入所有值可能要花费相当长的时间, 并且你很容易犯错。

Python中的列表推导结构如下:

list_variable = [x for x in iterable]

但是, 如何使用这种类似于公式的方式在Python中构建和使用这些构造?让我们深入一点。

Python中的列表理解:数学

幸运的是, Python为你提供了解决方案:它为你提供了一种实现数学符号的方法:列表理解。

请记住, 在数学中, 描述列表(或集合, 元组或向量)的常用方法是:

S = {x² : x in {0 ... 9}}
V = (1, 2, 4, 8, ..., 2¹²)
M = {x | x in S and x even}

换句话说, 你会发现上述定义实际上告诉你以下内容:

  • 序列S实际上是一个序列, 其中包含0到9之间的值, 该值被提高为2的幂。
  • 另一方面, 序列V包含值2, 该值增加到一定的幂。对于序列中的第一个元素, 它是0, 第二个元素是1, 依此类推, 直到达到12。
  • 最后, 序列M包含序列S中的元素, 但仅包含偶数元素。

如果上述定义让你头疼, 请查看这些定义将产生的实际列表:

S = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
V = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096}
M = {0, 4, 16, 36, 64}

你可以清楚地看到每个列表的结果以及其中描述的操作!

现在, 你已经了解了列表背后的一些数学知识, 你可以使用列表推导来翻译或实现在Python中构造列表的数学符号!看一下下面的代码行:

所有这些看起来都与你刚刚看到的数学定义非常相似, 对吧?

如果你此时有点迷茫, 请不要担心。即使你不是数学天才, 如果你花时间研究它们, 这些列表理解也很容易。再仔细研究一下你在上面的代码块中看到的Python代码。

你会看到该代码告诉你:

  • 列表S由上面在第一部分中阅读的方括号构成。在这些括号中, 你看到有一个元素x, 它被提高到10的幂。现在, 你只需要知道需要将多少个值(以及哪些值!)提高到2的幂。在range(10)中确定。考虑所有这些, 你可以得出将所有数字从0扩展到9的幂的2的幂。
  • 列表V包含基值2, 该基值增加到一定的幂。就像以前一样, 现在你需要知道使用哪种电源或我将完全使用它。你会看到i在这种情况下是range(13)的一部分, 这意味着你从0开始直到12。所有这些都意味着你的列表将具有13个值-这些值将提高2次0, 1, 2, …一直到12。
  • 最后, 列表M包含以下元素, 它们是S的一部分, 当且仅当它们可以被2除而没有任何剩余。模数必须为0。换句话说, 列表M由存储在列表S中的相等值构成。

现在你已经看到了所有这些内容, 这更有意义了吗?

总结与练习

简而言之, 你将在所有这些代码行中看到几个元素:

  • 方括号是Python列表的签名;
  • for关键字, 后跟一个象征列表项的变量;和
  • in关键字, 后跟一个序列(可以是列表!)。

这就是你在本节开头看到的一段代码:

list_variable = [x for x in iterable]

现在轮到你开始着手使用Python进行列表理解了!让我们紧贴你之前看到的数学列表:

Q = {$ x ^ 3 $:{0 … 10}中的x

列表理解作为…的替代

列表理解可以完全替代循环, lambda函数以及map(), filter()和reduce()函数。而且, 对于某些人来说, 列表理解甚至可以更容易理解和在实践中使用!你将在下一节中阅读有关此内容的更多信息!

但是, 如果你想进一步了解Python中的函数和lambda函数, 请查看我们的Python函数教程。

对于循环

你可能已经知道, 你可以使用for循环将一段代码重复固定的次数。列表理解实际上是for循环的不错选择, 因为它们更紧凑。考虑以下以变量号开头的示例, 该变量号定义为从0到10的范围(不包括在内)。

请记住, 传递给range()函数的数字实际上是要生成的整数数目, 当然, 该数目从零开始。这意味着range(10)将返回[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。

# Initialize `numbers`
numbers = range(10)

如果现在要对数字中的每个元素执行操作, 则可以使用for循环执行此操作, 就像这样:

# Initialize `new_list`
new_list = []

# Add values to `new_list`
for n in numbers:
    if n%2==0:
        new_list.append(n**2)

# Print `new_list`
print(new_list)
[0, 4, 16, 36, 64]

一切都很好, 但是现在考虑下面的列表理解示例, 在该示例中, 你基本上使用更紧凑的符号进行了相同的操作:

# Create `new_list` 
new_list = [n**2 for n in numbers if n%2==0]

# Print `new_list`
print(new_list)
[0, 4, 16, 36, 64]

让我们通过一个小测试来研究列表理解和for循环之间的性能差异:你可以使用timeit库快速设置此代码, 该库可用于以简单的方式对少量Python代码进行计时。在这种情况下, 你将测试的一小段代码是for循环, 为了方便起见, 你将其放入一个名为power_two()的函数中, 以及上面已确定的确切的列表理解。

请注意, 你还传递了要考虑的执行次数。在这种情况下, 在number参数中将其设置为10000。

# Import `timeit`
import timeit
# Print the execution time
print(timeit.timeit('[n**2 for n in range(10) if n%2==0]', number=10000))
0.05234622399802902
# Define `power_two()` 
def power_two(numbers):
    for n in numbers:
        if n%2==0:
            new_list.append(n**2)
    return new_list

# Print the execution time 
print(timeit.timeit('power_two(numbers)', globals=globals(), number=10000))
0.07795589299712447

请注意, 在最后这段代码中, 你还添加了globals参数, 这将导致代码在当前的全局名称空间中执行。如果你具有用户定义的函数(UDF)(例如上例中的power_two()函数), 这将非常方便。或者, 你也可以传递包含导入语句的设置参数。你可以在此处了解更多信息。

提示:查阅srcmini的Python循环教程, 了解有关Python循环的更多信息。

具有map(), filter()和reduce()的Lambda函数

Lambda函数也称为”匿名函数”或”无名称的函数”。这意味着你只能在创建函数时使用这种类型的函数。 Lambda函数从Python中的lambda关键字借用其名称, 该关键字用于声明这些函数而不是标准def关键字。

通常将这些函数与map(), filter()和reduce()函数一起使用。

如何与Lambda函数组合替换map()

你可以像下面的示例一样重写map()和lambda函数的组合:

# Initialize the `kilometer` list 
kilometer = [39.2, 36.5, 37.3, 37.8]

# Construct `feet` with `map()`
feet = map(lambda x: float(3280.8399)*x, kilometer)

# Print `feet` as a list 
print(list(feet))
[128608.92408000001, 119750.65635, 122375.32826999998, 124015.74822]

现在, 考虑到上一节中已阅读的组件, 你可以轻松地用列表推导替换定义英尺变量的功能组合。

  • 从方括号开始。
  • 然后在以下方括号中添加lambda函数的主体:float(3280.8399)* x。
  • 接下来, 添加for关键字, 并确保重复序列元素x, 这已经通过添加lambda函数的主体来引用了。
  • 不要忘记指定x的来源:添加in关键字, 然后添加从中获取x的顺序。在这种情况下, 你将变换公里清单的元素。

如果执行所有这些操作, 将得到以下结果:

# Convert `kilometer` to `feet` 
feet = [float(3280.8399)*x for x in kilometer]

# Print `feet`
print(feet)
[128608.92408000001, 119750.65635, 122375.32826999998, 124015.74822]

filter()和Lambda函数列出理解

既然你已经知道可以轻松地将map()函数与lambda函数结合使用, 那么你还可以使用lambda函数处理包含Python filter()函数的代码, 并对其进行重写。

考虑以下示例:

# Map the values of `feet` to integers 
feet = list(map(int, feet))

# Filter `feet` to only include uneven distances 
uneven = filter(lambda x: x%2, feet)

# Check the type of `uneven`
type(uneven)

# Print `uneven` as a list
print(list(uneven))
[122375, 124015]

要重写以上示例中的代码行, 你实际上可以使用两个列表推导, 分别存储在foot和不均匀变量中。

首先, 重写map()函数, 该函数用于将英尺列表的元素转换为整数。然后, 处理filter()函数:取得lambda函数的主体, 使用for和in关键字在逻辑上将x和foot连接起来:

# Constructing `feet` 
feet = [int(x) for x in feet]

# Print `feet`
print(feet)

# Get all uneven distances
uneven = [x%2 for x in feet]

# Print `uneven`
print(uneven)
[128608, 119750, 122375, 124015]
[0, 0, 1, 1]

减少Python中的reduce()和Lambda函数

最后, 你还可以将与reduce()函数一起使用的lambda函数重写为更紧凑的代码行。看下面的例子:

# Import `reduce` from `functools` 
from functools import reduce

# Reduce `feet` to `reduced_feet`
reduced_feet = reduce(lambda x, y: x+y, feet)

# Print `reduced_feet`
print(reduced_feet)
[128608, 119750, 122375, 124015]
494748

请注意, 在Python 3中, reduce()函数已移至functools包中。因此, 你需要导入模块才能使用它, 就像上面的代码示例一样。

上面的代码块很长, 不是吗?

让我们重写这段代码!

小心!你需要考虑到不能使用y。列表推导仅适用于一个元素, 例如在本教程的许多示例中都看到的x。

你将如何解决这个问题?

好吧, 在这种情况下, 诸如sum()之类的聚合函数可能会派上用场:

# Construct `reduced_feet`
reduced_feet = sum([x for x in feet])

# Print `reduced_feet`
print(reduced_feet)
494748

请注意, 考虑到这一点, 在重写reduce()函数和lambda函数时结合使用聚合函数是有意义的:与使用聚合函数限制要记录的记录数时, SQL非常相似你在运行查询后会回来。在这种情况下, 你可以使用sum()函数以英尺为单位汇总元素, 以仅获取一个确定的值!

请注意, 即使这种方法在SQL中的性能可能不如在SQL中, 但绝对是你使用Python时要走的路!

具有条件的列表理解

既然你已经了解了Python中列表推导的基础知识, 该是时候借助条件函数来调整列表推导的控制流程了。

# Define `uneven`
uneven = [x/2 for x in feet if x%2==0]

# Print `uneven` 
print(uneven)
[64304.0, 59875.0]

请注意, 你可以使用Python for循环轻松重写上述代码块!

# Initialize and empty list `uneven` 
uneven = []

# Add values to `uneven` 
for x in feet:
    if x % 2 == 0:
        x = x / 2
        uneven.append(x)

# Print `uneven` 
print(uneven)
[64304.0, 59875.0]

多条件

现在你已经了解了如何添加条件, 是时候将以下for循环转换为带有条件的列表理解了。

divided = []

for x in range(100):
    if x%2 == 0 :
        if x%6 == 0:
            divided.append(x)

请注意, 以下for循环包含两个条件!请仔细考虑你将如何解决此问题。

divided = [x for x in range(100) if x % 2 == 0 if x % 6 == 0]

print(divided)
[0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]

如果-其他条件

当然, 处理涉及多个条件的条件更为普遍。没错, 你会经常看到是否与elif等结合使用。现在, 如果你打算重写代码, 该如何处理?

看一下下面的示例, 该示例在for循环中具有更复杂的条件:

[x+1 if x >= 120000 else x+5 for x in feet]
[128609, 119755, 122376, 124016]

现在看下面的代码块, 它是上面代码的重写:

for x in feet:  
    if x >= 120000:
        x + 1
    else: 
        x+5

你会看到这基本上是相同的代码, 但是经过了重组:现在, 最后一个英尺的x会初始化for循环。此后, 如果x> = 120000, 则添加条件;如果此条件为True, 则添加要执行的代码行:x +1。如果条件为False, 则执行列表理解中的最后代码:x + 5。

嵌套列表推导

除条件语句外, 你还可以通过将其嵌套在其他列表理解中来调整列表理解。当你要使用列表列表时, 这很方便:例如, 使用嵌套列表推导, 生成列表列表, 将列表列表换位或将列表列表展平为常规列表变得非常容易。

看下面的例子:

list_of_list = [[1, 2, 3], [4, 5, 6], [7, 8]]

# Flatten `list_of_list`
[y for x in list_of_list for y in x]
[1, 2, 3, 4, 5, 6, 7, 8]

你可以将一个非常简单的列表列表分配给变量list_of_list。在下一行中, 你将执行一个列表理解, 该列表返回一个普通列表。实际发生的情况是, 你获取list_of_list中嵌套列表(x)的列表元素(y), 并返回包含在x中的那些列表元素y的列表。

你会看到, 在嵌套列表推导示例中使用的大多数关键字和元素与在简单列表推导示例中使用的关键字和元素相似:

  • 方括号
  • 两个为关键字, 后跟一个变量, 该变量表示列表列表的一项(x)和一个嵌套列表的列表项(y);和
  • 输入两个关键字, 后跟一个列表列表(list_of_list)和一个列表项(x)。

大多数组件只使用了两次, 你就可以再上一层(或更深一层, 取决于你的外观!)。

要花一些时间才能习惯, 但这很简单, 对吧?

现在让我们考虑另一个示例, 在该示例中, 你还可以使用两对方括号来更改嵌套列表理解的逻辑:

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

[[row[i] for row in matrix] for i in range(3)]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

现在练习:将上面的代码块重写为嵌套的for循环。如果你需要一些有关如何解决此问题的指导, 请转到本教程的前面部分之一。

transposed = []

for i in range(3):
     transposed_row = []
     for row in matrix:
            transposed_row.append(row[i])
     transposed.append(transposed_row)

当你需要创建实际上是矩阵的列表列表时, 也可以使用嵌套列表推导。查看以下示例:

matrix = [[0 for col in range(4)] for row in range(3)]

matrix
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

提示:在Python中练习循环技巧, 然后将上述代码块重写为嵌套的for循环!

你可以在下面找到解决方案。

for x in range(3):
    nested = []
    matrix.append(nested)
    for row in range(4):
        nested.append(0)

如果你想完成一些额外的工作, 请将此for循环翻译为while循环。你可以在下面找到解决方案:

x = 0
matrix =[]

while x < 3:
    nested = []
    y = 0
    matrix.append(nested)
    x = x+1
    while y < 4:
        nested.append(0)
        y= y+1

最后, 很高兴知道你还可以使用诸如int()之类的函数将脚列表中的条目转换为整数。通过将[int(x)x英尺为单位]封装在另一个列表理解中, 你可以很容易地构造一个矩阵或列表列表:

[[int(x) for x in feet] for x in feet]
[[128608, 119750, 122375, 124015], [128608, 119750, 122375, 124015], [128608, 119750, 122375, 124015], [128608, 119750, 122375, 124015]]

掌握数据科学的Python

恭喜!在本教程的最后, 你已经解决了列表推导问题, 这是Python在数据科学中经常使用的一种机制。既然你已经了解了这种机制的工作原理, 那么你就可以准备处理字典, 集合, ……理解了!

不要忘记, 你可以使用srcmini的日常练习模式每天练习Python技能!你可以在仪表板上找到它。如果你还不知道日常练习模式, 请在这里阅读!

尽管列表理解可以使我们的代码更简洁, 但是确保最终代码尽可能可读是很重要的, 因此应避免使用很长的单行代码以确保我们的代码易于使用。

赞(0)
未经允许不得转载:srcmini » Python列表深入理解教程

评论 抢沙发

评论前必须登录!