Python 语言语法非常强大和富有表现力。因此,用 Python 表达算法很简洁。也许这就是它在机器学习中流行的原因,因为我们在开发机器学习模型时需要进行大量的实验。
如果你是 Python 新手,但有其他编程语言的经验,你有时会发现 Python 语法可以理解但很奇怪。如果你习惯了用 C++ 或 Java 编写代码,然后转到 Python,你的程序很可能不是 Pythonic 的。
在本教程中,我们将介绍 Python 中一些常见的语言特性,这些特性使其有别于其他编程语言。
使用我的新书《Python for Machine Learning》来启动你的项目,其中包括分步教程和所有示例的 Python 源代码文件。
让我们开始吧。
Python 中的一些语言特性
图片作者:David Clode,保留部分权利。
教程概述
本教程分为两部分;它们是
- 运算符
- 内置数据结构
- 特殊变量
- 内置函数
运算符
Python 中使用的大多数运算符与其他语言相同。优先级表如下,摘自 Python 语言参考手册第 6 章 (https://docs.pythonlang.cn/3/reference/expressions.html)
运算符 | 描述 |
---|---|
(表达式…), [表达式…], {键: 值…}, {表达式…} | 绑定或带括号的表达式、列表显示、字典显示、集合显示 |
x[索引], x[索引:索引], x(参数…), x.属性 | 下标、切片、调用、属性引用 |
await x | await 表达式 |
** | 幂运算 |
+x, -x, ~x | 正、负、按位非 |
*, @, /, //, % | 乘法、矩阵乘法、除法、整除、取模 |
+, – | 加法和减法 |
<<, >> | 移位 |
& | 按位与 |
^ | 按位异或 |
| | 按位或 |
in, not in, is, is not, <, <=, >, >=, !=, == | 比较,包括成员测试和身份测试 |
not x | 布尔非 |
和 | 布尔与 |
或者 | 布尔或 |
if – else | 条件表达式 |
lambda | Lambda 表达式 |
:= | 赋值表达式 |
与其他语言的一些主要区别
- 布尔运算符使用单词表示,而位运算符使用字符
&
、^
和|
- 幂运算使用
2**3
- 整除使用
//
,而除法/
总是返回浮点数 - 三元运算符:如果你熟悉 C 语言中的表达式
(x)?a:b
,在 Python 中我们将其写作a if x else b
- 比较两个事物是否相等可以使用
==
或is
。==
运算符与其他语言中的相等性比较相同,但is
更严格,保留用于判断两个变量是否指向同一个对象
在 Python 中,我们允许在比较运算符中进行链式比较。例如,要测试一个值是否在 -1 和 +1 之间,我们可以这样做
1 2 |
if value > -1 and value < 1: ... |
但我们也可以这样做
1 2 |
if -1 < value < 1: ... |
内置数据结构
与其他许多语言一样,Python 中也有整数和浮点数据类型。但也有复数(例如,`3+1j`)、布尔常量(`True` 和 `False`)、字符串以及一个空类型 `None`。
但是 Python 作为一种语言的强大之处在于它内置了容器类型:Python 数组被称为“列表”,它会自动扩展。关联数组(或哈希表)被称为“字典”。我们还有“元组”作为只读列表,“集合”作为唯一项的容器。例如,在 C++ 中,你需要 STL 来提供这些功能。
“dict”数据结构可能是 Python 中最强大的数据结构,它为我们编写代码提供了一些便利。例如,在狗和猫的图像分类问题中,我们的机器学习模型可能只给出 0 或 1 的值,如果你想打印名称,我们可以这样做
1 2 3 4 |
value = 0 # 这是从模型中获取的 value_to_name = {0: "cat", 1: "dog"} print("结果是 %s" % value_to_name[value]) |
1 |
结果是 cat |
在这种情况下,我们利用字典 `value_to_name` 作为查找表。同样,我们也可以利用字典来构建一个计数器
1 2 3 4 5 6 7 8 |
sentence = "Portez ce vieux whisky au juge blond qui fume" counter = {} for char in sentence: if char not in counter: counter[char] = 0 counter[char] += 1 print(counter) |
1 |
{'P': 1, 'o': 2, 'r': 1, 't': 1, 'e': 5, 'z': 1, ' ': 8, 'c': 1, 'v': 1, 'i': 3, 'u': 5, 'x': 1, 'w': 1, 'h': 1, 's': 1, 'k': 1, 'y': 1, 'a': 1, 'j': 1, 'g': 1, 'b': 1, 'l': 1, 'n': 1, 'd': 1, 'q': 1, 'f': 1, 'm': 1} |
这将构建一个名为 `counter` 的字典,它将每个字符映射到该字符在句子中出现的次数。
Python 列表也具有强大的语法。与其他一些语言不同,我们可以将任何东西放入列表中
1 2 3 |
A = [1, 2, "fizz", 4, "buzz", "fizz", 7] A += [8, "fizz", "buzz", 11, "fizz", 13, 14, "fizzbuzz"] print(A) |
1 |
[1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz'] |
我们可以使用 `+` 连接列表。在上面,我们使用 `+=` 来扩展列表 `A`。
Python 列表具有切片语法。例如,在上面的 `A` 中,我们可以使用 `A[1:3]` 表示元素 1 和 2,即 `[2, "fizz"]`,`A[1:1]` 是一个空列表。事实上,我们可以为切片赋值来插入或删除一些元素。例如
1 2 3 |
... A[2:2] = [2.1, 2.2] print(A) |
1 |
[1, 2, 2.1, 2.2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz'] |
然后,
1 2 3 |
... A[0:2] = [] print(A) |
1 |
[2.1, 2.2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz', 11, 'fizz', 13, 14, 'fizzbuzz'] |
元组的语法与列表相似,只是它使用括号定义
1 |
A = ("foo", "bar") |
元组是不可变的。这意味着一旦定义,就不能修改它。在 Python 中,如果你用逗号将几个事物连接在一起,它就被认为是元组。这意味着我们可以用非常简洁的语法交换两个变量
1 2 3 4 5 |
a = 42 b = "foo" print("a 是 %s;b 是 %s" % (a,b)) a, b = b, a # 交换 print("交换后,a 是 %s;b 是 %s" % (a,b)) |
1 2 |
a 是 42;b 是 foo 交换后,a 是 foo;b 是 42 |
最后,正如你在上面的例子中看到的,Python 字符串支持即时替换。通过类似于 C 语言中 `printf()` 函数的模板语法,我们可以使用 `%s` 替换字符串,或使用 `%d` 替换整数。我们也可以使用 `%.3f` 替换一个保留 3 位小数的浮点数。下面是一个例子
1 2 3 4 |
template = " %d 的平方根是 %.3f" n = 10 answer = template % (n, n**0.5) print(answer) |
1 |
10 的平方根是 3.162 |
但这只是其中一种方法。上述功能也可以通过 f-string 和 format() 方法实现。
特殊变量
Python 中预定义了一些“特殊变量”。`__name__` 告诉当前命名空间,`__file__` 告诉脚本的文件名。更多的特殊变量会在对象内部找到,但几乎所有这些变量通常都不应该直接使用。作为约定俗成(也就是说,仅仅是一种习惯,没有人阻止你这样做),我们用下划线或双下划线作为前缀来命名内部变量(顺便说一句,双下划线被一些人读作“dunder”)。如果你来自 C++ 或 Java,这些变量等同于类的私有成员,尽管它们在技术上并非私有。
一个值得注意的“特殊”变量,你可能会经常在 Python 代码中看到的是 `_`,仅仅是一个下划线字符。它约定俗成地表示一个我们不关心的变量。如果你不关心一个变量,为什么还需要它呢?那是因为有时你会保留一个函数的返回值。例如,在 pandas 中,我们可以遍历数据框的每一行
1 2 3 4 5 6 |
import pandas as pd A = pd.DataFrame([[1,2,3],[2,3,4],[3,4,5],[5,6,7]], columns=["x","y","z"]) print(A) for _, row in A.iterrows(): print(row["z"]) |
1 2 3 4 5 6 7 8 9 10 |
x y z 0 1 2 3 1 2 3 4 2 3 4 5 3 5 6 7 3 4 5 7 |
在上面,我们可以看到数据框有三列,“x”、“y”和“z”,并且行由 0 到 3 索引。如果我们调用 `A.iterrows()`,它将逐一返回索引和行,但我们不关心索引。我们可以创建一个新变量来保存它但不用它。为了明确我们不打算使用它,我们使用 `_` 作为变量来保存索引,而行则存储到变量 `row` 中。
想开始学习机器学习 Python 吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
内置函数
在 Python 中,少数函数被定义为内置函数,而其他功能则通过其他包提供。所有内置函数的列表可在 Python 标准库文档中找到 (https://docs.pythonlang.cn/3/library/functions.html)。以下是 Python 3.10 中定义的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
abs() aiter() all() any() anext() ascii() bin() bool() breakpoint() bytearray() bytes() callable() chr() classmethod() compile() complex() delattr() dict() dir() divmod() enumerate() eval() exec() filter() float() format() frozenset() getattr() globals() hasattr() hash() help() hex() id() input() int() isinstance() issubclass() iter() len() list() locals() map() max() memoryview() min() next() object() oct() open() ord() pow() print() property() range() repr() reversed() round() set() setattr() slice() sorted() staticmethod() str() sum() super() tuple() type() vars() zip() __import__() |
并非所有函数都每天使用,但有些函数尤其值得注意
zip()
允许您将多个列表组合在一起。例如,
1 2 3 4 5 |
a = ["x", "y", "z"] b = [3, 5, 7, 9] c = [2.1, 2.5, 2.9] for x in zip(a, b, c): print(x) |
1 2 3 |
('x', 3, 2.1) ('y', 5, 2.5) ('z', 7, 2.9) |
如果你想“旋转”一个列表的列表,它也很方便,例如:
1 2 3 4 5 |
a = [['x', 3, 2.1], ['y', 5, 2.5], ['z', 7, 2.9]] p,q,r = zip(*a) print(p) print(q) print(r) |
1 2 3 |
('x', 'y', 'z') (3, 5, 7) (2.1, 2.5, 2.9) |
enumerate()
很方便,可以让你为列表中的项目编号,例如:
1 2 3 |
a = ["quick", "brown", "fox", "jumps", "over"] for num, item in enumerate(a): print("项目 %d 是 %s" % (num, item)) |
1 2 3 4 5 |
项目 0 是 quick 项目 1 是 brown 项目 2 是 fox 项目 3 是 jumps 项目 4 是 over |
如果你不使用 `enumerate`,这相当于以下代码
1 2 3 |
a = ["quick", "brown", "fox", "jumps", "over"] for num in range(len(a)): print("项目 %d 是 %s" % (num, a[num])) |
与其他语言相比,Python 中的 for 循环是迭代预定义范围,而不是在每次迭代中计算值。换句话说,没有直接等同于以下 C 语言 for 循环的代码
1 2 3 |
for (i=0; i<100; ++i) { ... } |
在 Python 中,我们必须使用 `range()` 来实现相同的功能
1 2 |
for i in range(100): ... |
类似地,有一些函数可以操作列表(或类似列表的数据结构,Python 称之为“可迭代对象”)。
max(a)
:查找列表a
中的最大值min(a)
:查找列表a
中的最小值sum(a)
:计算列表a
中值的总和reverse(a)
:从列表a
的末尾开始迭代sorted(a)
:返回列表a
的副本,其中元素按排序顺序排列
我们将在下一篇文章中详细介绍这些内容。
延伸阅读
以上仅重点介绍了 Python 的一些关键特性。当然,没有比 Python.org 官方文档更权威的文档了;所有初学者都应该从 Python 教程开始,并查阅语言参考以获取语法细节,以及标准库以获取 Python 安装附带的其他库
- Python 教程 – https://docs.pythonlang.cn/3/tutorial/index.html
- Python 语言参考 – https://docs.pythonlang.cn/3/reference/index.html
- Python 标准库 – https://docs.pythonlang.cn/3/library/index.html
对于书籍,《学习 Python》是 Lutz 的一本古老而优秀的入门书。之后,《流畅的 Python》可以帮助你更好地理解语言的内部结构。但是,如果你想要快速上手,Al Sweigart 的书可以通过示例帮助你快速掌握这门语言。一旦你熟悉了 Python,你可能想从《Python Cookbook》中学习特定任务的快速技巧。
- 学习 Python, 第五版,Mark Lutz 著,O’Reilly,2013,https://www.amazon.com/dp/1449355730/
- 流畅的 Python,Luciano Ramalho 著,O’Reilly,2015,https://www.amazon.com/dp/1491946008/
- 用 Python 自动化无聊的工作,第二版,Al Sweigart 著,No Starch Press,2019,https://www.amazon.com/dp/1593279922/
- Python Cookbook, 第三版,David Beazley 和 Brian K. Jones 著,O’Reilly,2013,https://www.amazon.com/dp/1449340377/
总结
在本教程中,您了解了 Python 的一些独特特性。具体来说,您学习了
- Python 提供的运算符
- 内置数据结构的一些用法
- 一些常用内置函数及其用处
对于计数器示例,这样更好
from collections import Counter
sentence = "Portez ce vieux whisky au juge blond qui fume"
counter = Counter(sentence)
print(counter)
谢谢,但这里的重点是演示如何将字典用作计分板
> 与其他语言相比,Python 中的 for 循环是迭代预定义范围,而不是在每次迭代中计算值。换句话说,没有直接等同于以下 C 语言 for 循环的代码
它们在哪些方面不相等?在每个循环中,都有一个整数
i
在整个循环范围内,其值从 0 到 99(包括 0 和 99)。它们不相等的部分在哪里?这里的等价性是在低级实现上。你没有在每次循环中进行评估和赋值。Python 的 for 循环更像是扫描一个集合,而不是计算每一步
i=0
当 i<10 时
打印(i)
i+=1
通过
一如既往,精彩的文章。谢谢!
谢谢。很高兴你喜欢。
你好 Brian……非常欢迎!如果您有任何问题需要我们帮助,请告诉我们。
此致,
如果你使用格式化字符串,你的打印语句会更易读
感谢您的建议。
感谢您的帖子,对 Pythonic 的方式使事情变得简单,这是一个很好的复习和提醒
感谢您的反馈和友善的话语,Prashanth!请告诉我们您最感兴趣的机器学习领域。
此致,
你的 pandas 示例中的列标题偏移了,x 在索引上方,可能会让读者感到困惑。
感谢您的反馈 Vasanth!