附录A:Python参考

本附录提供了本书中涵盖的最重要的Python概念的快速参考。有关Python的更多信息,请查看网上许多免费的可用资源。

1. 什么是Python?

Python是一种在1990年代开发的计算机编程语言,现在是世界上使用最广泛的语言之一。Python是创建应用程序、Web服务、视频游戏、数字音乐和艺术等事物的好选择。它也是处理大量数据的伟大工具,这使其成为数据科学和机器学习应用程序的流行工具。

2. Python程序是什么样的?

Python程序由根据严格的语法规则编写的文本行组成。编程语言的规则称为其语法。Python具有相对简洁和简单的语法,易于阅读和编写,这是它如此受初学者和专家欢迎的原因之一。这是一个在TunePad内运行的两行程序。该程序打印一些文本,然后在钢琴上播放一个中央C音符:

print('This is a program') # 打印文本到控制台
playNote(60) # 播放中央C一个节拍

3. 注释

在上面的代码中,某些文本出现在每一行的井号(#)符号之后。这个文本称为注释——程序员添加的自由格式注释,使他们的代码更容易理解。注释文本被Python忽略,所以您可以在一行中的井号符号后写任何您想要的内容。您也可以在行的开头使用井号来临时禁用代码。这称为”注释掉”代码。

4. 什么是语法错误?

如果您不严格按照Python的规则键入程序,您会收到一个名为语法错误的错误消息。以下是TunePad中语法错误的样子:

playnote(60)

语法错误通常包括显示问题所在的行号。如果您收到语法错误,这意味着Python感到困惑——它不理解您告诉它要做什么。因为Python感到困惑,Python生成的语法错误对人类程序员来说也常常没有太大意义。在这个例子中,Python感到困惑是因为我们写了playnote(小写”n”)而不是playNote(大写”N”)。

这是另一个语法错误,程序员使用了智能引号(““)而不是直上直下的引号。不幸的是,当您使用智能引号时,Python会感到困惑。

print("hello
syntax error")

这是最后一个语法错误。这个很棘手,因为问题实际上在第1行,即使语法错误说第2行。实际问题是第1行缺少右括号。

playNote(60
rest(1)

5. 函数

您在Python中做的几乎一切都与调用函数有关。函数(有时称为命令或指令)告诉Python做某事或计算一个值。例如,print函数告诉Python输出一行文本。在早期计算机时代,print函数调用实际上会将输出发送到物理打印机,在纸带上打印文本行。现代语言做的本质上是相同的事情,只是它们将文本打印到屏幕而不是纸张。

5.1 调用函数

每个函数调用都有三个部分:

  1. 首先,您必须写函数的名称。函数有一个单词的名称(没有空格),可以由字母、数字和下划线_字符组成。如果您想要一个多词函数,通常用下划线字符分隔单词,如:my_multi_word_function(),或者您可以将每个新单词大写,如playNote。

  2. 其次,您必须在函数名称后包含括号。

  3. 最后,您包含要传递给函数的任何参数。参数提供额外信息或告诉函数如何行为。例如,上面的print语句有一个参数,即要输出的文本。这个playNote函数告诉TunePad播放中央C(音符60)两个节拍。第一个参数是音符,第二个是音符的持续时间(附录A1.4)。

5.2 可选参数

有时参数是可选的,意味着如果您不指定,它们会提供默认值。对于playNote,只有第一个参数(音符编号)是必需的。如果您不传递第二个参数,它假定值为1个节拍。您还可以在函数调用中包含参数的名称。例如,所有这四行都做相同的事情;它们播放一个音符1个节拍。前两个使用没有名称的参数。后两个包含参数的名称,后跟等号(=),后跟参数值。

playNote(60) # beats参数是可选的
playNote(60, 1) # 将beats参数设置为1
playNote(60, beats = 1) # 为beats使用参数名称
playNote(note = 60, beats = 1) # 为note和beats使用参数名称

5.3 返回值

函数也可用于计算值或产生结果。当函数产生结果时,称为返回值。例如,random函数计算0.0到1.0之间的随机十进制数。这在音乐中特别有用,可以创造更人性化的感觉。在Python中,random函数是也称为random的模块的一部分,必须首先导入。

from random import random # 导入random函数
duration = random() # 将持续时间设置为0.0到1.0之间的值
playNote(60, duration + 1) # 播放具有随机持续时间的音符

5.4 定义自己的函数

您也可以使用def关键字在Python中定义自己的函数。一旦定义了函数,您就可以像使用任何其他函数一样使用它。例如,下面的代码定义了两个名为chorus和groove的函数。您可以给函数任何您想要的名称,只要它们是一个单词长(没有空格)并且只包含字母、数字和下划线字符(_)。函数名称不能以数字开头。

def chorus():
    playNote(60)
    playNote(61)
    playNote(65)

def groove():
    playNote(0, beats = 0.5)
    playNote(4, beats = 0.5)
    playNote(2, beats = 0.5)
    playNote(4, beats = 0.5)
    playNote(0, beats = 0.5)
    playNote([0, 4], beats = 0.5) # 底鼓和踩镲双重踢
    playNote(2, beats = 0.5)
    playNote(4, beats = 0.5)

Python使用缩进来弄清楚代码的哪些部分在函数内部,哪些在函数外部。在上面的例子中,每个函数内的代码缩进四个空格(附录A1.5)。

一旦函数被定义,我们就可以像调用任何其他函数一样调用它:

chorus()
chorus()
groove()

5.5 定义带参数的函数

您还可以定义接受参数值的函数。参数就像您可以在函数内部使用的特殊变量(有关变量的更多信息,请参见下一节)。这是一个接受两个参数作为输入值的函数的简单示例。第一个是要播放的音符,第二个是音符持续时间。

def playThreeNotes(note, duration):
    playNote(note, beats = duration)
    playNote(note, beats = duration)
    playNote(note, beats = duration)

playThreeNotes(60, 2) # 播放音符60三次,每次2个节拍

5.6 定义带可选参数的函数

可以通过为函数的某些参数提供默认值来使它们可选。我们可以更改playThreeNotes函数,使duration参数具有预定义的值。

def playThreeNotes(note, duration = 1):
    playNote(note, beats = duration)
    playNote(note, beats = duration)
    playNote(note, beats = duration)

现在当我们调用函数时,我们可以决定是否提供持续时间:

# 前四个是等价的
playThreeNotes(60, 1)
playThreeNotes(60)
playThreeNotes(60, duration = 1)
playThreeNotes(note = 60, duration = 1)

# 这两个不等价
playThreeNotes(61, 2)
playThreeNotes(61)

5.7 定义带返回值的函数

您可以使用return关键字定义产生结果的函数。函数可以返回您想要的任何类型的值(有关不同类型,请参见第7节)。如果函数没有return语句,它会自动产生一个称为None的值。

def square(number):
    return number * number

square(6) # 返回36
square(9) # 返回81
square(-1) # 返回1

6. 变量

变量是您在Python程序中赋予某些信息的名称。您可以将变量视为一种昵称或别名。例如,左边的代码播放鼓模式而没有变量,右边的代码播放相同的东西但有变量。注意变量如何帮助使代码更容易理解,因为它们为各种鼓声音提供了描述性名称,而不仅仅是数字。

# 没有变量
playNote(0)
playNote(4)
playNote(2)
playNote(4)

# 使用变量
kick = 0
hat = 4
snare = 2

playNote(kick)
playNote(hat)
playNote(snare)
playNote(hat)

在右边的版本中,我们在第1行定义了一个名为kick的变量,在第2行定义了一个名为hat的变量,在第3行定义了一个名为snare的变量。每个变量都初始化为表示相应鼓声音的不同数值。也可以通过在程序中稍后为其分配不同的数字来更改变量的值。

kick = 0
playNote(kick)
kick = 1 # 将kick设置为不同的值
playNote(kick)

变量名称可以是您想要的任何名称,只要它们是一个单词长(没有空格)并且只包含字母、数字和下划线字符(_)。变量名称不能以数字开头,也不能与任何现有的Python关键字相同。

7. 数据类型

变量可以保存不同类型的数据。Python中有五种常见的数据类型:

name = "C major" # 文本值(字符串)
coda = False # 值为True或False(布尔值)
outro = None # 表示没有任何值的值
note = 17 # 整数(int)
duration = 1.75 # 十进制数(浮点数)

我们可以在程序运行时更改变量的值。我们也可以在为变量分配新值时更改其数据类型。Python通过声明变量的方式决定变量是什么类型。这对于数字数据类型有时可能令人困惑,因为某些数学运算符的行为取决于变量是整数还是十进制(浮点)数。

7.1 字符串

您可以将字符串视为文本或字符列表。例如:“Hello, I’m a string”有18个字符,从”H”开始,到”g”结束,包括空格。Python使用双引号(“)或单引号(’)定义字符串(记住智能引号不起作用)。

# 您可以使用双引号或单引号创建字符串
first_name = 'Ella'
last_name = "Fitzgerald"

您可以使用索引表示法访问字符串中的单个字符。例如,这两行代码从last_name变量中获取单个字母。注意Python使用0作为字符串中第一个字符的索引。

letter = last_name[0] # letter等于'F'
letter = last_name[3] # letter等于'z'

7.2 布尔值

第二种数据类型称为布尔值。布尔值是只能为True或False的值。布尔值在代码中问是或否的问题很有用,这是编程中的常见事情。

7.3 浮点数

浮点数(或float)是带有小数点的实数,可以是正数、负数或零。

7.4 整数

整数(或int)是没有小数点的整数,可以是正数、负数或零。

7.5 None

None值是一种说变量没有当前值的方式,这在编程中有时也很有用。

8. 列表

变量非常适合处理单个数据片段,但我们经常想要同时处理许多数据元素。编程语言强大的原因之一是它们可以对存储在计算机内存中的大型数据数组进行操作。在Python中,有一种称为列表的数据类型,让我们跟踪任意数量的数据元素。我们可以使用方括号创建列表,其中包含逗号分隔的数据元素。列表在TunePad中对于播放和弦(一次多个音符)非常有用。

例如,这行代码使用列表播放C大调和弦。

playNote([60, 64, 67], beats = 4)

和弦的音符用方括号[60, 64, 67]括起来以创建列表。正如到目前为止我们介绍的其他数据类型一样,您可以使用变量来引用列表。

Cmajor = [60, 64, 67]
Dminor = [62, 65, 69]

playNote(Dminor)
playNote(Cmajor, beats = 4)

此代码创建两个名为Cmajor和Dminor的变量,每个变量都保存表示和弦音符的数字列表。Python列表是多功能的;它们带有各种有用的功能,我们在下面描述其中最重要的功能。

8.1 访问单个列表元素

一旦定义了列表,您通常希望能够为访问单个元素。在Python中,列表的第一个元素存储在索引0处,您可以像这样访问它:

first_note = Cmajor[0] # 获取Cmajor和弦的第一个音符
playNote(first_note)

第二个元素在索引1处,第三个在索引2处,依此类推。列表的第一个元素存储在索引0处的事实需要一些时间来习惯,并且是初学者常见的困惑来源。

要从列表末尾访问元素,Python使用负数。列表的最后一个元素存储在索引-1处,倒数第二个元素存储在索引-2处,依此类推。

last_note = Cmajor[-1] # 获取Cmajor和弦的最后一个音符
playNote(last_note)

8.2 更改列表元素

索引也可用于修改列表元素。如果我们想更改Cmajor和弦的第一个音符,我们可以使用此语法。

Cmajor[0] = 48 # 更改音阶的第一个音符

8.3 列表的长度

len()函数告诉您列表有多长。

print(len(Dminor)) # 输出和弦中的音符数

8.4 添加到列表

Python列表可以增长和缩小。要将元素添加到列表末尾,请使用append函数。此函数是列表的一部分,使用稍微不同的语法。我们必须将列表后跟句点(点),后跟append函数名称。append函数接受一个参数,即要添加到列表末尾的值。

Dminor.append(72) # 在Dminor和弦末尾添加C音符
print(Dminor) # 打印[62, 65, 69, 72]
print(len(Dminor)) # 打印4

我们还可以使用insert函数将元素插入列表中的任意位置。为了更改示例,让我们尝试一个单词列表而不是数字。

words = ["cat", "dog", "mouse", "horse", "goat"]
words.insert(1, "elephant") # elephant现在将是第二个元素

要在列表的最开头插入元素,我们将使用索引0的insert。

words.insert(0, "moose") # moose现在将是第一个元素

8.5 从列表中删除

有多种方法可以从列表中删除元素。最直接的方法之一是在列表上调用remove函数。

words = ["cat", "dog", "mouse", "horse", "goat"]
words.remove("dog") # 第二个元素现在将被删除。

第二种选择是调用pop函数以删除并返回列表的最后一个元素。

words.pop() # 返回"goat",现在将从列表中删除。

pop函数也可以带有一个索引调用,该索引说明要删除哪个元素。

words = ["cat", "dog", "mouse", "horse", "goat"]
words.pop(2) # 删除并返回"mouse"

您可以使用clear函数删除列表的所有元素。

words = ["cat", "dog", "mouse", "horse", "goat"]
words.clear() # 列表现在为空

8.6 选择子列表

Python提供了强大的工具来访问较大列表的段或切片。在实践中,这看起来类似于列表索引,但允许我们返回元素列表而不是单个元素。我们通过指定开始和停止索引来执行此操作,用冒号分隔:

myList[start:stop]

我们可以像使用任何其他列表一样使用切片操作的结果:

scale = [60, 62, 64, 65, 67, 69, 71, 72]
print(scale[2:4]) # 打印[64, 65]

for note in scale[0:5]:
    playNote(note)

切片都不需要这些参数。如果省略stop参数,那么我们的切片会一直到列表末尾。如果省略start参数,切片从列表开头开始。由于切片返回指定元素的副本,如果我们想复制整个列表,我们将省略start和stop参数:

myList[:]
语法 示例 说明
myList[start:stop] scale[2:4] 返回从start到stop-1的元素列表
myList[start:] scale[2:] 返回从start到列表末尾的元素列表
myList[:stop] scale[:5] 返回从0到stop-1的元素列表
myList[:] scale[:] 返回完整列表的副本

8.7 洗牌

您可以使用random模块中的shuffle函数像洗牌一样随机洗牌Python列表。这对于播放随机琶音之类的事情很有用。

from random import shuffle

notes = [60, 62, 64, 65, 67, 69, 71] # C大调音阶
shuffle(notes) # 随机重新排序音阶

8.8 选择

您可以使用random模块中的choice函数从列表中选择一个随机元素。

from random import choice

cards = [0, 1, 2, 3, 4, 5, 6, 7, 8]
my_card = choice(cards) # 从列表中随机选择一个数字

8.9 反转

您可以使用列表对象的reverse函数反转列表的顺序。

notes = [60, 62, 64, 65, 67, 69, 71] # C大调音阶
notes.reverse() # 反转音阶的顺序

for note in notes: # 从高音到低音播放音符
    playNote(note)

8.10 连接列表

您可以使用加号(+)将两个列表连接在一起以创建更长的列表。

Cmaj = [60, 64, 67]
Dmin = [61, 64, 68]
combined = Cmaj + Dmin # 结果为[60, 64, 67, 61, 64, 68]

8.11 排序列表

您可以使用sort函数按字母或数字顺序对列表进行排序。

words = ["cat", "dog", "mouse", "horse", "goat"]
words.sort() # 现在将按顺序排列:cat, dog, goat, horse, mouse

numbers = [4, 3, 5, 2, 9]
numbers.sort() # 现在将按顺序排列[2, 3, 4, 5, 9]

9. 字典

在Python中,字典或映射是由键引用的无序数据集。这些键与音乐调性不同。它们更像是打开锁门的钥匙。每个不同的钥匙打开自己的门。

字典在编程中极其有用,因为它们提供了一种按名称存储多个数据元素的简单方法。例如,如果我们想为音乐流媒体服务存储信息,我们可能需要保存歌曲名称、艺术家、发行日期、流派、唱片公司、歌曲长度和专辑封面。字典为您提供了一种在单个数据对象中存储所有这些数据元素的简单方法。

track_info = {
    "artist" : "Herbie Hancock",
    "album" : "Head Hunters",
    "label" : "Columbia Records",
    "genre" : "Jazz-Funk",
    "year" : 1973,
    "track" : "Chameleon",
    "length" : 15.75
}

字典使用花括号定义,键和值用冒号分隔。不同的条目用逗号分隔。定义字典后,我们可以使用关联的键更改现有值或添加新值。类似于我们使用索引访问列表中的值的方式,我们使用方括号和键来访问字典中的元素。

release_date = track_info['year']
track_info['year'] = 1974 # 用新值更新字典

我们还可以使用相同的语法向字典添加值。

track_info["artwork"] = "https://images.ssl-images-amz.com/images/81KRhL.jpg"

因为键”artwork”尚未在字典中使用,所以它创建一个新的键值对。如果”artwork”已经添加,它将更改现有值。需要注意的一件事是,字典中的值可以是任何数据类型,包括字符串、数字、列表甚至其他字典。字典键可以是字符串或数值,但它们对于每个存储的值必须是唯一的。

10. range函数

range函数用于生成有序的数字序列。这对于编码中的许多事情都很有用,特别是当我们想要连续重复一组操作多次时。range有三种常见变体:

  • 变体1:range(count)
  • 变体2:range(start, stop)
  • 变体3:range(start, stop, step)

在第一个版本中,range采用单个参数,告诉它数字序列应该有多长。例如,range(5)生成一个五个元素长的有序数字集,从0开始,一直到(但不包括)5:

0, 1, 2, 3, 4

在第二个版本中,range采用两个参数,起始值和停止值。结果序列将以第一个参数开始,一直到(但不包括)第二个参数。

range(0, 7) → 0, 1, 2, 3, 4, 5, 6
range(100, 105) → 100, 101, 102, 103, 104
range(50, 40) → 空
range(50, 50) → 空
range(-5, 0) → -5, -4, -3, -2, -1

如果第二个参数小于或等于第一个参数,则序列将不包含任何值。

range的最终版本采用第三个参数,该参数指定序列的步长(或跳过计数)。例如,如果您想从0到10以2计数,您可以使用此语句:

range(0, 10, 2) → 0, 2, 4, 6, 8

使用第三种形式,您还可以使用负步长向后计数。

range(10, 0, -1) → 10, 9, 8, 7, 6, 5, 4, 3, 2, 1

11. for循环

我们对计算机编程的原因之一是它们可以快速且无错误地执行重复和令人厌烦的任务,重复(或循环)的能力是几乎所有编程语言的核心部分。Python中有几种不同的循环,但最常见的之一称为for循环。以下是for循环的基本结构。带下划线的文本将被我们在下面例子中可以看到的实际代码替换:

for loop_variable in list:
    ...do something...

这是一个具体的例子:

notes = [60, 64, 67] # C大调和弦
for n in notes:
    playNote(n)

循环以for关键字开始,它告诉Python我们正在启动一个循环。下一部分称为循环变量。这是一种特殊类型的变量,Python将一次一个地分配给列表的每个元素。我们可以为循环变量使用任何有效的变量名。接下来是in关键字,后跟列表本身。此列表可以是变量名、生成列表的函数或表达式,或者内联定义的列表。

为了更清楚,下面这三个循环每个都做完全相同的事情(一次播放一个C小调和弦的音符):

notes = [60, 63, 67] # C小调和弦
for n in notes: # 列表是一个变量
    playNote(n)

for n in [60, 63, 67]: # 列表是内联定义的
    playNote(n)

for n in majorChord(60): # 函数生成列表
    playNote(n)

循环语法的下一部分是冒号字符,它告诉Python我们将启动一个代码块,每次循环重复时都会运行。在上面的例子中,我们只在循环内做了一件事,但您可以包含任意多行代码。

例如,此循环打印出名称列表,然后打印所有名称组合的总字符长度。

total = 0
names = ['Herbie', 'Miles', 'Ella']

for name in names:
    print(name)
    total = total + len(name)

print(total)

Python使用缩进来弄清楚代码的哪些部分在循环内,哪些在循环外。在上面的例子中,第4行和第5行各缩进四个空格,这使它们成为循环中重复的代码部分。第6行没有缩进,这意味着它只在循环完成重复后运行一次。如果运行此代码,输出是:

Herbie
Miles
Ella
15

注意我们在for循环中使用的列表可以包含任何数据类型,而不仅仅是数字。

11.1 带range函数的for循环

使用for循环最常见的方式之一是与range函数结合使用,以重复固定次数的操作。当我们用代码创建音乐时,这种循环对于踩镲滚奏和其他重复模式之类的事情很有用(附录A1.7):

带有range函数的for循环: - 以关键字for开始 - 包含循环变量名称;这可以是您想要的任何内容(上面是”i”) - 包含关键字in - 包含range函数 - 说明要重复多少次(上面是16次) - 包含冒号: - 包含缩进四个空格的代码块

缩进的代码块重复range指定的总次数。每次循环运行时,变量增加1。

如果我们想做一些事情,比如创建一个渐强,其中每个音符变得越来越响,循环变量在这里也会派上用场。

for vol in range(10, 101, 10):
    playNote(50, velocity = vol)

…或者渐弱,其中音量变得越来越小:

for vol in range(100, 0, -10):
    playNote(58, velocity = vol)

11.2 嵌套循环

循环可以以复杂的方式与其他编程结构结合。一个常见的工具是将一个循环嵌套在另一个循环中。例如,假设我们想生成一个军鼓上升器,它播放四组八个音符,每一轮新音符的播放速度是前一轮的两倍。这创建了一个加速模式,看起来像这样(附录A1.8)。

一种方法是使用嵌套for循环。

duration = 1.0 # 每个音符的持续时间
for i in range(4): # 4组音符
    for j in range(8): # 每组有8个音符
        playNote(2, beats = duration)
    duration = duration / 2 # 将音符持续时间减半

外循环重复四次(第2行),内循环重复八次(第3行)。这意味着第4行的playNote被调用8 × 4 = 32次。每个音符的长度由我们在第1行声明的duration变量决定。此变量以值1.0开始,但在外循环的每次迭代中,我们将值减半。

12. 条件逻辑

条件逻辑是基于布尔值在程序中提问的一种方式。如果值为True,Python将运行一个代码块。如果值为False,它将运行不同的代码块。

12.1 if语句

条件逻辑最基本的形式是if语句。如果值为True,if语句运行一个代码块,否则跳过它:

verbose = True

if verbose:
    print("I have a lot to say")

此示例总是打印出”I have a lot to say”。如果verbose变量为False,它不会打印出任何内容。if语句适用于任意长的代码块:

# 假设drum_fill变量已经定义
if drum_fill:
    for i in range(4):
        playNote(2, beats = 0.25)

在这种情况下,如果drum_fill变量为True,Python运行for循环以播放四个军鼓声音。在if语句中,输入值可以是任何评估为布尔值的表达式或函数。这是一个使用比较和逻辑运算符的例子(参见下面的第13节)。

if (getPlayhead() < 2) or (getPlayhead() > 3):
    playNote(11)

if语句也可以相互嵌套以创建更复杂的条件逻辑。

if testA:
    if testB:
        # 如果testA和testB都为True,运行一些代码
        print('A and B are both True')
    # 如果testA为True,运行一些代码
    print('A is True. B may or may not be True')

12.2 if else语句

if语句的一种变体允许我们在布尔值评估为False时运行替代代码。这是一个音乐示例,根据情况播放一些音符或休止。

# ...假设decoration已经定义
if decoration:
    playNote(24)
    playNote(27)
else:
    rest(2)

在这个例子中,如果decoration为True,则调用两个playNote函数。否则,如果decoration为False,则调用rest语句。

12.3 if Elif语句

在if语句的第三种变体中,让我们将任意数量的替代条件链接在一起。此示例使用称为==的逻辑运算符来测试两个值是否相同。

volume = "medium"

if volume == "loud":
    playNote(60, velocity = 100)
elif volume == "medium":
    playNote(60, velocity = 80)
elif volume == "soft":
    playNote(60, velocity = 30)
else:
    playNote(60, velocity = 0)

在此代码中,elif代表”else if”,允许我们问一系列问题。首先评估为True的任何if或elif语句都会运行;其他语句将被忽略。如果没有任何内容为True,则如果提供了else条件,则运行该条件。这些例子还不是很有趣,但让我们将if语句与逻辑运算符结合使用时,事情会变得更有趣。

13. Python运算符

Python使用运算符来比较或转换值。一些最常见的运算符测试相等性和不等性,或执行算术运算,如加法、减法和乘法。运算符通常可以使用括号组合成复合语句。

13.1 比较运算符

比较运算符比较两个数值,并根据结果返回True或False。

代码 名称 说明 示例
== 等于 如果两个值相同则返回True;否则返回False a == b
!= 不等于 如果两个值不相同则为True a != b
> 大于 如果第一个数字大于第二个则为True a > b
< 小于 如果第一个数字小于第二个则为True a < b
>= 大于或等于 如果第一个数字大于或等于第二个则为True a >= b
<= 小于或等于 如果第一个数字小于或等于第二个则为True a <= b

13.2 逻辑运算符

逻辑运算符将布尔值组合成复合逻辑语句。

代码 说明 示例
and 当两个值都为True时返回True;否则返回False a and b
or 如果任一值为True则返回True;如果两个值都为False则返回False a or b
not 如果值为False则返回True;如果值为True则返回False not a

13.3 包含运算符

包含运算符允许您测试值是否包含在列表或序列中。

代码 说明 示例
in 如果值包含在列表中则返回True 65 in notes
not in 如果值不包含在列表中则返回True 65 not in notes

13.4 算术运算符

算术运算符对数字执行常见的数学运算。

代码 名称 说明 示例
+ 加法 将两个数字相加 a + b
- 减法 从第一个数字中减去第二个数字 a - b
* 乘法 将两个数字相乘 a * b
/ 除法 将第一个数字除以第二个。除法总是返回十进制数 a / b
// 整数除法 将第一个数字除以第二个,向下舍入到最接近的整数。如果两个数字都是整数,则结果将是整数。否则结果是十进制 a // b
** 指数 将第一个数字提升到第二个数字的幂。示例显示x³ x ** 3
% 模数或余数 执行除法并返回余数。例如,3.5 % 2将是1.5。或5 % 3将是2 3.5 % 2

13.5 运算优先级

Python对于如何使用运算符评估表达式有精确的规则。其中一些规则在数学课上是熟悉的——乘法和除法优先于加法和减法。为了避免混淆,最好将不同的运算符括在括号中。

x ** 3 > 15 or y < 8.3 / x + 0.5 # 令人困惑!!
((x ** 3) > 15) or (y < (8.3 / (x + 0.5))) # 不那么令人困惑

14. while循环

while循环是一种重复一组指令直到满足某个条件的方式。当我们事先不知道需要循环多少次时,这很有用。这是一个循环直到声音变得太安静而听不见的例子:

volume = 100

while volume > 20:
    playNote(10, beats = 0.5, velocity = volume)
    volume = volume * 0.9 # 减少到音量的90%

15. 对象和类

Python中几乎所有的东西都是对象:列表、变量甚至函数。对象是数据的抽象。它们描述如何表示和操作数据。Python还允许程序员灵活地定义自己的对象,称为类。类让程序员能够精确地构建他们正在处理的数据,并定义用于处理该数据的函数(称为方法)。属于类的单个数据片段称为字段。这些字段可以由任何东西组成:数字、字符串、列表、字典甚至其他类的实例。

假设我们想定义一个类来描述任何人。这个类应该有两个字段:name和age。我们可以通过定义称为__init__的特殊方法来指定这些字段的初始值。此方法将采用参数self和我们想要指定的任何字段。self参数指定方法正在对对象起作用。我们还可以定义我们想要类具有的任何其他字段。

class Person:
    def __init__(self, name, age):
        self.Name = name
        self.Age = age
        self.Species = "human"

让我们快速深入了解此代码。在第1行,class关键字告诉Python我们正在定义一个新类,我们称之为”Person”。在第2行,我们开始定义初始化函数,当我们想创建对象的新实例时调用它。此函数采用self以及我们人的姓名和年龄字段。在第3行和第4行,我们为对象创建实际字段,并将这些字段设置为用户传入的值。当我们想在类定义内使用这些字段内的值时,比如在方法中,我们使用self.fieldName。如果我们想在定义之外访问它们,我们可以使用variable.fieldName。定义类后,我们可以通过像函数一样调用它来创建此类的实例:

# 创建Person的实例并设置为变量
p1 = Person("Miles Davis", 42)
print(p1.Age) # 输出:"42"

这个例子还不是特别有用,但我们可以向类添加方法来处理数据。让我们定义ageInMonths方法,它返回人的年龄(以月为单位)。像我们的__init__函数一样,这也将采用参数self。因为我们的对象已经有一个age字段,我们的方法不需要接受任何其他参数。方法声明的其余部分看起来很像典型的函数定义。

class Person:
    def __init__(self, name, age):
        self.Name = name
        self.Age = age
        self.Species = "human"
    
    def ageInMonths(self):
        return self.Age * 12

# 创建Person的实例并设置为变量
p1 = Person("Stevie Wonder", 42)
print(p1.ageInMonths()) # 输出:504

类的概念是一个强大的工具。上面的例子有些微不足道,所以现在考虑一个封装音乐调性想法的类。您将如何使用它?这个对象可能有什么字段?您如何封装我们在第5章和第6章中定义的用于处理音阶和和弦的函数?

16. 模块

使用Python(或任何现代、功能齐全的语言)的好处之一是,它为您提供了各种现有的代码库,帮助您完成常见的编程任务。通常这些库被分组到称为模块的集合中。Python有一组称为标准库的大模块集,但它还允许您开发自己的模块,当您作为编码人员构建工具包时这很有用。有多种方法可以将模块代码导入您自己的项目中。

首先,您可以将整个模块导入到您的代码中,这允许您使用该模块中的函数、类和变量。

import random

如果我们想使用此模块中的特定项目,我们必须引用其命名空间。命名空间为我们提供了一种干净的方式来跟踪一段代码的来源。这对于较大的软件变得重要。引用命名空间减少了歧义,特别是如果不同的模块具有同名函数或类!在下面的例子中,random是命名空间(即我们导入的模块),randint是我们正在调用的函数:

x = random.randint(0, 10)

我们还可以从模块导入特定项目。如果我们这样做,我们不必使用命名空间。

from random import randint

x = randint(0, 10)

我们还可以使用as关键字定义新的命名空间:

import random as rand

x = rand.randint(0, 1)

最后,如果我们不想为我们正在导入的代码使用命名空间,我们可以使用*符号从模块导入所有代码:

from random import *

在TunePad中,每个乐器就像一个模块。如果您在一个乐器或定义单元格中定义的函数具有有效的Python变量名,则可以将它们导入另一个乐器或定义单元格中。这成为制作具有重复元素的歌曲的强大工具。