Python 数据分析(PYDA)第三版(一)(1)https://developer.aliyun.com/article/1482368
内省
在变量前或后使用问号(?
)将显示有关对象的一些常规信息:
In [1]: b = [1, 2, 3] In [2]: b? Type: list String form: [1, 2, 3] Length: 3 Docstring: Built-in mutable sequence. If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified. In [3]: print? Docstring: print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout. sep: string inserted between values, default a space. end: string appended after the last value, default a newline. flush: whether to forcibly flush the stream. Type: builtin_function_or_method
这被称为对象内省。如果对象是函数或实例方法,则如果定义了文档字符串,它也将显示出来。假设我们编写了以下函数(您可以在 IPython 或 Jupyter 中重现):
def add_numbers(a, b): """ Add two numbers together Returns ------- the_sum : type of arguments """ return a + b
然后使用?
显示文档字符串:
In [6]: add_numbers? Signature: add_numbers(a, b) Docstring: Add two numbers together Returns ------- the_sum : type of arguments File: <ipython-input-9-6a548a216e27> Type: function
?
还有一个最终的用途,就是在 IPython 命名空间中进行搜索,类似于标准的 Unix 或 Windows 命令行。与通配符(*
)结合的一系列字符将显示所有与通配符表达式匹配的名称。例如,我们可以获取包含load
的顶级 NumPy 命名空间中的所有函数列表:
In [9]: import numpy as np In [10]: np.*load*? np.__loader__ np.load np.loads np.loadtxt
2.3 Python 语言基础
在本节中,我将为您概述基本的 Python 编程概念和语言机制。在下一章中,我将更详细地介绍 Python 数据结构、函数和其他内置工具。
语言语义
Python 语言设计的一个重要特点是其对可读性、简单性和明确性的强调。有些人甚至将其比作“可执行的伪代码”。
缩进,而不是大括号
Python 使用空格(制表符或空格)来结构化代码,而不是像 R、C++、Java 和 Perl 等许多其他语言那样使用大括号。考虑一个排序算法中的for
循环:
for x in array: if x < pivot: less.append(x) else: greater.append(x)
冒号表示缩进代码块的开始,之后所有代码都必须缩进相同的量,直到块的结束。
无论你喜欢还是讨厌,对于 Python 程序员来说,有意义的空白是一个事实。虽然一开始可能会感到陌生,但希望你能逐渐习惯它。
注意
我强烈建议使用四个空格作为默认缩进,并用四个空格替换制表符。许多文本编辑器都有一个设置,可以自动将制表符替换为空格(请这样做!)。IPython 和 Jupyter 笔记本会在冒号后的新行自动插入四个空格,并用四个空格替换制表符。
正如你现在所看到的,Python 语句也不需要以分号结尾。但是,分号可以用来在单行上分隔多个语句:
a = 5; b = 6; c = 7
在一行上放置多个语句通常在 Python 中是不鼓励的,因为这可能会使代码变得不太可读。
一切都是对象
Python 语言的一个重要特点是其对象模型的一致性。每个数字、字符串、数据结构、函数、类、模块等都存在于 Python 解释器中的自己的“盒子”中,这被称为Python 对象。每个对象都有一个关联的类型(例如整数、字符串或函数)和内部数据。实际上,这使得语言非常灵活,因为即使函数也可以像任何其他对象一样对待。
注释
由井号(井号)#
引导的任何文本都会被 Python 解释器忽略。这通常用于向代码添加注释。有时您可能还想排除某些代码块而不删除它们。一种解决方案是注释掉代码:
results = [] for line in file_handle: # keep the empty lines for now # if len(line) == 0: # continue results.append(line.replace("foo", "bar"))
注释也可以出现在执行代码的行之后。虽然一些程序员更喜欢将注释放在特定代码行之前的行中,但有时这样做也是有用的:
print("Reached this line") # Simple status report
函数和对象方法调用
使用括号调用函数并传递零个或多个参数,可选地将返回的值赋给一个变量:
result = f(x, y, z) g()
Python 中几乎每个对象都有附加的函数,称为方法,这些函数可以访问对象的内部内容。您可以使用以下语法调用它们:
obj.some_method(x, y, z
函数可以接受位置和关键字参数:
result = f(a, b, c, d=5, e="foo")
我们稍后会更详细地看一下这个。
变量和参数传递
在 Python 中赋值变量(或名称)时,您正在创建对等号右侧显示的对象的引用。在实际操作中,考虑一个整数列表:
In [8]: a = [1, 2, 3]
假设我们将a
赋给一个新变量b
:
In [9]: b = a In [10]: b Out[10]: [1, 2, 3]
在一些语言中,对b
的赋值将导致数据[1, 2, 3]
被复制。在 Python 中,a
和b
实际上现在指向同一个对象,即原始列表[1, 2, 3]
(请参见图 2.5 的模拟)。您可以通过向a
附加一个元素,然后检查b
来证明这一点:
In [11]: a.append(4) In [12]: b Out[12]: [1, 2, 3, 4]
图 2.5:同一对象的两个引用
了解 Python 中引用的语义以及何时、如何以及为什么数据被复制,在处理 Python 中的大型数据集时尤为重要。
注意
赋值也被称为绑定,因为我们正在将一个名称绑定到一个对象。已经分配的变量名称有时可能被称为绑定变量。
当您将对象作为参数传递给函数时,将创建新的本地变量引用原始对象,而不进行任何复制。如果在函数内部将一个新对象绑定到一个变量,那么它不会覆盖函数外部(“父范围”)具有相同名称的变量。因此,可以更改可变参数的内部。假设我们有以下函数:
In [13]: def append_element(some_list, element): ....: some_list.append(element)
然后我们有:
In [14]: data = [1, 2, 3] In [15]: append_element(data, 4) In [16]: data Out[16]: [1, 2, 3, 4]
动态引用,强类型
Python 中的变量没有与之关联的固有类型;通过赋值,变量可以引用不同类型的对象。以下情况没有问题:
In [17]: a = 5 In [18]: type(a) Out[18]: int In [19]: a = "foo" In [20]: type(a) Out[20]: str
变量是特定命名空间内对象的名称;类型信息存储在对象本身中。一些观察者可能匆忙得出结论,认为 Python 不是一种“类型化语言”。这是不正确的;考虑这个例子:
In [21]: "5" + 5 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-21-7fe5aa79f268> in <module> ----> 1 "5" + 5 TypeError: can only concatenate str (not "int") to str
在某些语言中,字符串'5'
可能会被隐式转换(或转换)为整数,从而得到 10。在其他语言中,整数5
可能会被转换为字符串,从而得到连接的字符串'55'
。在 Python 中,不允许这种隐式转换。在这方面,我们说 Python 是一种强类型语言,这意味着每个对象都有一个特定的类型(或类),隐式转换只会在某些允许的情况下发生,例如:
In [22]: a = 4.5 In [23]: b = 2 # String formatting, to be visited later In [24]: print(f"a is {type(a)}, b is {type(b)}") a is <class 'float'>, b is <class 'int'> In [25]: a / b Out[25]: 2.25
在这里,即使b
是一个整数,它也会被隐式转换为浮点数进行除法运算。
了解对象的类型很重要,能够编写能够处理许多不同类型输入的函数也很有用。您可以使用isinstance
函数检查对象是否是特定类型的实例:
In [26]: a = 5 In [27]: isinstance(a, int) Out[27]: True
如果要检查对象的类型是否在元组中存在,isinstance
可以接受一个类型元组:
In [28]: a = 5; b = 4.5 In [29]: isinstance(a, (int, float)) Out[29]: True In [30]: isinstance(b, (int, float)) Out[30]: True
属性和方法
Python 中的对象通常具有属性(存储在对象“内部”的其他 Python 对象)和方法(与对象关联的函数,可以访问对象的内部数据)。它们都可以通过语法访问:
In [1]: a = "foo" In [2]: a.<Press Tab> capitalize() index() isspace() removesuffix() startswith() casefold() isprintable() istitle() replace() strip() center() isalnum() isupper() rfind() swapcase() count() isalpha() join() rindex() title() encode() isascii() ljust() rjust() translate() endswith() isdecimal() lower() rpartition() expandtabs() isdigit() lstrip() rsplit() find() isidentifier() maketrans() rstrip() format() islower() partition() split() format_map() isnumeric() removeprefix() splitlines()
属性和方法也可以通过getattr
函数按名称访问:
In [32]: getattr(a, "split") Out[32]: <function str.split(sep=None, maxsplit=-1)>
虽然我们在本书中不会广泛使用getattr
函数和相关函数hasattr
和setattr
,但它们可以非常有效地用于编写通用的可重用代码。
鸭子类型
通常,您可能不关心对象的类型,而只关心它是否具有某些方法或行为。这有时被称为鸭子类型,源自谚语“如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子。”例如,如果对象实现了迭代器协议,则可以验证该对象是否可迭代。对于许多对象,这意味着它具有一个__iter__
“魔术方法”,尽管检查的另一种更好的方法是尝试使用iter
函数:
In [33]: def isiterable(obj): ....: try: ....: iter(obj) ....: return True ....: except TypeError: # not iterable ....: return False
对于字符串以及大多数 Python 集合类型,此函数将返回True
:
In [34]: isiterable("a string") Out[34]: True In [35]: isiterable([1, 2, 3]) Out[35]: True In [36]: isiterable(5) Out[36]: False
导入
在 Python 中,模块只是一个包含 Python 代码的扩展名为*.py*的文件。假设我们有以下模块:
# some_module.py PI = 3.14159 def f(x): return x + 2 def g(a, b): return a + b
如果我们想要从同一目录中的另一个文件中访问some_module.py中定义的变量和函数,我们可以这样做:
import some_module result = some_module.f(5) pi = some_module.PI
或者:
from some_module import g, PI result = g(5, PI)
通过使用as
关键字,您可以为导入指定不同的变量名称:
import some_module as sm from some_module import PI as pi, g as gf r1 = sm.f(pi) r2 = gf(6, pi)
二进制运算符和比较
大多数二进制数学运算和比较使用其他编程语言中常用的数学语法:
In [37]: 5 - 7 Out[37]: -2 In [38]: 12 + 21.5 Out[38]: 33.5 In [39]: 5 <= 2 Out[39]: False
查看表 2.1 以获取所有可用的二进制运算符。
表 2.1:二进制运算符
操作 | 描述 |
a + b |
将a 和b 相加 |
a - b |
从a 中减去b |
a * b |
将a 乘以b |
a / b |
将a 除以b |
a // b |
通过b 进行地板除法,去除任何小数余数 |
a ** b |
将a 提升到b 次方 |
a & b |
如果a 和b 都为True ,则为True ;对于整数,取位AND |
`a | b` |
a ^ b |
对于布尔值,如果a 或b 为True ,但不是两者都为True ;对于整数,取位异或 |
a == b |
如果a 等于b ,则为True |
a != b |
如果a 不等于b ,则为True |
a < b ,a <= b |
如果a 小于(小于或等于)b ,则为True |
a > b, a >= b |
如果a 大于(大于或等于)b ,则为True |
a is b |
如果a 和b 引用相同的 Python 对象,则为True |
a is not b |
如果a 和b 引用不同的 Python 对象,则为True |
要检查两个变量是否引用同一对象,请使用is
关键字。使用is not
来检查两个对象是否不相同:
In [40]: a = [1, 2, 3] In [41]: b = a In [42]: c = list(a) In [43]: a is b Out[43]: True In [44]: a is not c Out[44]: True
由于list
函数始终创建一个新的 Python 列表(即一个副本),我们可以确保c
与a
不同。与==
运算符不同,使用is
不同,因为在这种情况下我们有:
In [45]: a == c Out[45]: True
is
和is not
的常见用法是检查变量是否为None
,因为None
只有一个实例:
In [46]: a = None In [47]: a is None Out[47]: True
可变和不可变对象
Python 中的许多对象,如列表、字典、NumPy 数组和大多数用户定义的类型(类),都是可变的。这意味着它们包含的对象或值可以被修改:
In [48]: a_list = ["foo", 2, [4, 5]] In [49]: a_list[2] = (3, 4) In [50]: a_list Out[50]: ['foo', 2, (3, 4)]
其他,如字符串和元组,是不可变的,这意味着它们的内部数据不能被更改:
In [51]: a_tuple = (3, 5, (4, 5)) In [52]: a_tuple[1] = "four" --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-52-cd2a018a7529> in <module> ----> 1 a_tuple[1] = "four" TypeError: 'tuple' object does not support item assignment
请记住,仅因为您可以改变对象并不意味着您总是应该这样做。这些操作被称为副作用。例如,在编写函数时,任何副作用都应明确地在函数的文档或注释中向用户传达。如果可能的话,我建议尽量避免副作用并偏爱不可变性,即使可能涉及可变对象。
标量类型
Python 具有一小组内置类型,用于处理数字数据、字符串、布尔(True
或False
)值以及日期和时间。这些“单值”类型有时被称为标量类型,我们在本书中将它们称为标量。请参阅表 2.2 以获取主要标量类型的列表。日期和时间处理将单独讨论,因为这些由标准库中的datetime
模块提供。
表 2.2:标准 Python 标量类型
类型 | 描述 |
None |
Python 的“null”值(只存在一个None 对象的实例) |
str |
字符串类型;保存 Unicode 字符串 |
bytes |
原始二进制数据 |
float |
双精度浮点数(请注意没有单独的double 类型) |
bool |
布尔值True 或False |
int |
任意精度整数 |
数字类型
数字的主要 Python 类型是int
和float
。int
可以存储任意大的数字:
In [53]: ival = 17239871 In [54]: ival ** 6 Out[54]: 26254519291092456596965462913230729701102721
浮点数用 Python 的float
类型表示。在底层,每个都是双精度值。它们也可以用科学计数法表示:
In [55]: fval = 7.243 In [56]: fval2 = 6.78e-5
整数除法如果结果不是整数,将始终产生一个浮点数:
In [57]: 3 / 2 Out[57]: 1.5
要获得 C 风格的整数除法(如果结果不是整数,则丢弃小数部分),请使用地板除法运算符//
:
In [58]: 3 // 2 Out[58]: 1
字符串
许多人使用 Python 是因为其内置的字符串处理功能。您可以使用单引号'
或双引号"
(通常更喜欢双引号)编写字符串字面值:
a = 'one way of writing a string' b = "another way"
Python 字符串类型是str
。
对于带有换行符的多行字符串,可以使用三引号,即'''
或"""
:
c = """ This is a longer string that spans multiple lines """
这个字符串c
实际上包含四行文本可能会让您感到惊讶;在"""
之后和lines
之后的换行符包含在字符串中。我们可以使用c
上的count
方法来计算换行符的数量:
In [60]: c.count("\n") Out[60]: 3
Python 字符串是不可变的;您不能修改一个字符串:
In [61]: a = "this is a string" In [62]: a[10] = "f" --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-62-3b2d95f10db4> in <module> ----> 1 a[10] = "f" TypeError: 'str' object does not support item assignment
要解释此错误消息,请从下往上阅读。我们尝试用字母"f"
替换位置 10 处的字符(“项”),但对于字符串对象来说,这是不允许的。如果我们需要修改一个字符串,我们必须使用一个创建新字符串的函数或方法,比如字符串replace
方法:
In [63]: b = a.replace("string", "longer string") In [64]: b Out[64]: 'this is a longer string'
此操作后,变量a
保持不变:
In [65]: a Out[65]: 'this is a string'
许多 Python 对象可以使用str
函数转换为字符串:
In [66]: a = 5.6 In [67]: s = str(a) In [68]: print(s) 5.6
字符串是 Unicode 字符序列,因此可以像其他序列(如列表和元组)一样对待:
In [69]: s = "python" In [70]: list(s) Out[70]: ['p', 'y', 't', 'h', 'o', 'n'] In [71]: s[:3] Out[71]: 'pyt'
s[:3]
语法称为切片,对于许多种类的 Python 序列都有实现。稍后将更详细地解释这一点,因为它在本书中被广泛使用。
反斜杠字符\
是一个转义字符,意味着它用于指定特殊字符,如换行符\n
或 Unicode 字符。要编写带有反斜杠的字符串字面值,您需要对其进行转义:
In [72]: s = "12\\34" In [73]: print(s) 12\34
如果您有一个带有许多反斜杠且没有特殊字符的字符串,您可能会觉得有点烦人。幸运的是,您可以在字符串的前导引号前加上r
,这意味着应该按原样解释字符:
In [74]: s = r"this\has\no\special\characters" In [75]: s Out[75]: 'this\\has\\no\\special\\characters'
r
代表原始。
将两个字符串相加会将它们连接在一起并生成一个新字符串:
In [76]: a = "this is the first half " In [77]: b = "and this is the second half" In [78]: a + b Out[78]: 'this is the first half and this is the second half'
字符串模板或格式化是另一个重要主题。随着 Python 3 的出现,进行此操作的方式数量已经扩展,这里我将简要描述其中一个主要接口的机制。字符串对象具有一个format
方法,可用于将格式化参数替换为字符串中,生成一个新字符串:
In [79]: template = "{0:.2f} {1:s} are worth US${2:d}"
在这个字符串中:
{0:.2f}
表示将第一个参数格式化为带有两位小数的浮点数。{1:s}
表示将第二个参数格式化为字符串。{2:d}
表示将第三个参数格式化为精确整数。
要为这些格式参数替换参数,我们将一系列参数传递给format
方法:
In [80]: template.format(88.46, "Argentine Pesos", 1) Out[80]: '88.46 Argentine Pesos are worth US$1'
Python 3.6 引入了一个名为f-strings(即格式化字符串字面值)的新功能,可以使创建格式化字符串更加方便。要创建 f-string,只需在字符串字面值之前立即写入字符f
。在字符串中,用大括号括起 Python 表达式,以将表达式的值替换为格式化字符串中的值:
In [81]: amount = 10 In [82]: rate = 88.46 In [83]: currency = "Pesos" In [84]: result = f"{amount} {currency} is worth US${amount / rate}"
格式说明符可以在每个表达式后添加,使用与上面字符串模板相同的语法:
In [85]: f"{amount} {currency} is worth US${amount / rate:.2f}" Out[85]: '10 Pesos is worth US$0.11'
字符串格式化是一个深入的主题;有多种方法和大量选项和调整可用于控制结果字符串中的值的格式。要了解更多,请参阅官方 Python 文档。
字节和 Unicode
在现代 Python(即 Python 3.0 及更高版本)中,Unicode 已成为一流的字符串类型,以实现更一致地处理 ASCII 和非 ASCII 文本。在旧版本的 Python 中,字符串都是字节,没有任何明确的 Unicode 编码。您可以假设您知道字符编码来转换为 Unicode。这里是一个带有非 ASCII 字符的示例 Unicode 字符串:
In [86]: val = "español" In [87]: val Out[87]: 'español'
我们可以使用encode
方法将此 Unicode 字符串转换为其 UTF-8 字节表示:
In [88]: val_utf8 = val.encode("utf-8") In [89]: val_utf8 Out[89]: b'espa\xc3\xb1ol' In [90]: type(val_utf8) Out[90]: bytes
假设您知道bytes
对象的 Unicode 编码,您可以使用decode
方法返回:
In [91]: val_utf8.decode("utf-8") Out[91]: 'español'
现在最好使用 UTF-8 进行任何编码,但出于历史原因,您可能会遇到各种不同编码的数据:
In [92]: val.encode("latin1") Out[92]: b'espa\xf1ol' In [93]: val.encode("utf-16") Out[93]: b'\xff\xfee\x00s\x00p\x00a\x00\xf1\x00o\x00l\x00' In [94]: val.encode("utf-16le") Out[94]: b'e\x00s\x00p\x00a\x00\xf1\x00o\x00l\x00'
在处理文件时,最常见的是遇到bytes
对象,其中不希望将所有数据隐式解码为 Unicode 字符串。
布尔值
Python 中的两个布尔值分别写为True
和False
。比较和其他条件表达式的结果要么为True
,要么为False
。布尔值可以使用and
和or
关键字组合:
In [95]: True and True Out[95]: True In [96]: False or True Out[96]: True
当转换为数字时,False
变为0
,True
变为1
:
In [97]: int(False) Out[97]: 0 In [98]: int(True) Out[98]: 1
关键字not
可以将布尔值从True
翻转为False
,反之亦然:
In [99]: a = True In [100]: b = False In [101]: not a Out[101]: False In [102]: not b Out[102]: True
类型转换
str
、bool
、int
和float
类型也是可以用来将值转换为这些类型的函数:
In [103]: s = "3.14159" In [104]: fval = float(s) In [105]: type(fval) Out[105]: float In [106]: int(fval) Out[106]: 3 In [107]: bool(fval) Out[107]: True In [108]: bool(0) Out[108]: False
请注意,大多数非零值在转换为bool
时会变为True
。
None
None
是 Python 的空值类型:
In [109]: a = None In [110]: a is None Out[110]: True In [111]: b = 5 In [112]: b is not None Out[112]: True
None
也是函数参数的常见默认值:
def add_and_maybe_multiply(a, b, c=None): result = a + b if c is not None: result = result * c return result
日期和时间
内置的 Python datetime
模块提供了datetime
、date
和time
类型。datetime
类型结合了date
和time
中存储的信息,是最常用的类型:
In [113]: from datetime import datetime, date, time In [114]: dt = datetime(2011, 10, 29, 20, 30, 21) In [115]: dt.day Out[115]: 29 In [116]: dt.minute Out[116]: 30
给定一个datetime
实例,您可以通过在具有相同名称的datetime
上调用方法来提取等效的date
和time
对象:
In [117]: dt.date() Out[117]: datetime.date(2011, 10, 29) In [118]: dt.time() Out[118]: datetime.time(20, 30, 21)
strftime
方法将datetime
格式化为字符串:
In [119]: dt.strftime("%Y-%m-%d %H:%M") Out[119]: '2011-10-29 20:30'
字符串可以使用strptime
函数转换(解析)为datetime
对象:
In [120]: datetime.strptime("20091031", "%Y%m%d") Out[120]: datetime.datetime(2009, 10, 31, 0, 0)
查看表 11.2 以获取完整的格式规范列表。
当您聚合或以其他方式对时间序列数据进行分组时,偶尔会有必要替换一系列datetime
的时间字段,例如,将minute
和second
字段替换为零:
In [121]: dt_hour = dt.replace(minute=0, second=0) In [122]: dt_hour Out[122]: datetime.datetime(2011, 10, 29, 20, 0)
由于datetime.datetime
是不可变类型,这些方法总是会产生新对象。因此,在前面的例子中,dt
不会被replace
修改:
In [123]: dt Out[123]: datetime.datetime(2011, 10, 29, 20, 30, 21)
两个datetime
对象的差产生一个datetime.timedelta
类型:
In [124]: dt2 = datetime(2011, 11, 15, 22, 30) In [125]: delta = dt2 - dt In [126]: delta Out[126]: datetime.timedelta(days=17, seconds=7179) In [127]: type(delta) Out[127]: datetime.timedelta
输出timedelta(17, 7179)
表示timedelta
编码了 17 天和 7179 秒的偏移量。
将timedelta
添加到datetime
会产生一个新的偏移datetime
:
In [128]: dt Out[128]: datetime.datetime(2011, 10, 29, 20, 30, 21) In [129]: dt + delta Out[129]: datetime.datetime(2011, 11, 15, 22, 30)
控制流
Python 有几个内置关键字用于条件逻辑、循环和其他标准控制流概念,这些概念在其他编程语言中也可以找到。
if、elif 和 else
if
语句是最为人熟知的控制流语句类型之一。它检查一个条件,如果为True
,则评估后面的代码块:
x = -5 if x < 0: print("It's negative")
if
语句后面可以选择跟随一个或多个elif
代码块和一个全捕获的else
代码块,如果所有条件都为False
:
if x < 0: print("It's negative") elif x == 0: print("Equal to zero") elif 0 < x < 5: print("Positive but smaller than 5") else: print("Positive and larger than or equal to 5")
如果任何条件为True
,则不会继续执行任何elif
或else
代码块。使用and
或or
的复合条件,条件从左到右进行评估并会短路:
In [130]: a = 5; b = 7 In [131]: c = 8; d = 4 In [132]: if a < b or c > d: .....: print("Made it") Made it
在这个例子中,比较c > d
永远不会被评估,因为第一个比较是True
。
也可以链接比较:
In [133]: 4 > 3 > 2 > 1 Out[133]: True
for 循环
for
循环用于遍历集合(如列表或元组)或迭代器。for
循环的标准语法是:
for value in collection: # do something with value
您可以使用continue
关键字将for
循环推进到下一个迭代,跳过代码块的其余部分。考虑这段代码,它对列表中的整数求和并跳过None
值:
sequence = [1, 2, None, 4, None, 5] total = 0 for value in sequence: if value is None: continue total += value
可以使用break
关键字完全退出for
循环。这段代码将列表元素求和,直到达到 5 为止:
sequence = [1, 2, 0, 4, 6, 5, 2, 1] total_until_5 = 0 for value in sequence: if value == 5: break total_until_5 += value
break
关键字仅终止最内层的for
循环;任何外部的for
循环将继续运行:
In [134]: for i in range(4): .....: for j in range(4): .....: if j > i: .....: break .....: print((i, j)) .....: (0, 0) (1, 0) (1, 1) (2, 0) (2, 1) (2, 2) (3, 0) (3, 1) (3, 2) (3, 3)
正如我们将在更详细地看到的,如果集合或迭代器中的元素是序列(例如元组或列表),它们可以方便地在for
循环语句中解包为变量:
for a, b, c in iterator: # do something
while 循环
while
循环指定一个条件和一个要执行的代码块,直到条件评估为False
或循环被显式地使用break
结束为止:
x = 256 total = 0 while x > 0: if total > 500: break total += x x = x // 2
pass
pass
是 Python 中的“空操作”(或“什么也不做”)语句。它可以在不需要执行任何操作的代码块中使用(或作为尚未实现的代码的占位符);它仅仅是因为 Python 使用空格来分隔代码块:
if x < 0: print("negative!") elif x == 0: # TODO: put something smart here pass else: print("positive!")
范围
range
函数生成一系列均匀间隔的整数:
In [135]: range(10) Out[135]: range(0, 10) In [136]: list(range(10)) Out[136]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
可以给定起始点、终点和步长(可以是负数):
In [137]: list(range(0, 20, 2)) Out[137]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] In [138]: list(range(5, 0, -1)) Out[138]: [5, 4, 3, 2, 1]
正如您所看到的,range
生成的整数是直到但不包括终点的。range
的一个常见用途是通过索引迭代序列:
In [139]: seq = [1, 2, 3, 4] In [140]: for i in range(len(seq)): .....: print(f"element {i}: {seq[i]}") element 0: 1 element 1: 2 element 2: 3 element 3: 4
虽然您可以使用list
等函数将range
生成的所有整数存储在其他数据结构中,但通常默认的迭代器形式会是您想要的。这段代码将从 0 到 99,999 之间是 3 或 5 的倍数的所有数字相加:
In [141]: total = 0 In [142]: for i in range(100_000): .....: # % is the modulo operator .....: if i % 3 == 0 or i % 5 == 0: .....: total += i In [143]: print(total) 2333316668
虽然生成的范围可以任意大,但在任何给定时间内的内存使用可能非常小。
2.4 结论
本章简要介绍了一些基本的 Python 语言概念以及 IPython 和 Jupyter 编程环境。在下一章中,我将讨论许多内置数据类型、函数和输入输出工具,这些内容将在本书的其余部分中持续使用。
Python 数据分析(PYDA)第三版(一)(3)https://developer.aliyun.com/article/1482369