有一本学Python的书,也许你还没有关注到,它在bookauthority的Python类目中排名第三,要胜过太多太多的Python书。那就是《Python编程快速上手 让繁琐工作自动化》。
就它本身来说,这本书不会让你变成一个职业软件开发者,就像几节吉他课程不会让你变成一名摇滚巨星。但如果你是办公室职员、管理者、学术研究者,或使用计算机来工作或娱乐的任何人,你将学到编程的基本知识,这样就能将下面这样一些简单的任务自动化:
- 移动并重命名几千个文件,将它们分类,放入文件夹;
- 填写在线表单,不需要打字;
- 在网站更新时,从网站下载文件或复制文本;
- 让计算机向客户发出短信通知;
- 更新或格式化Excel电子表格;
- 检查电子邮件并发出预先写好的回复。
对人来说,这些任务简单,但很花时间。它们通常很琐碎、很特殊,没有现成的软件可以完成。有一点编程知识,就可以让计算机为你完成这些任务。
本书没有设计成参考手册,它是初学者指南。编码风格有时候违反最佳实践(例如,有些程序使用全局变量),但这是一种折中,让代码更简单,以便学习。
下面分享一下第一章节,希望你的Python编程语言可以从这里开始。
Python基础
Python编程语言有许多语法结构、标准库函数和交互式开发环境功能。好在,你可以忽略大多数内容。你只需要学习部分内容,就能编写一些方便的小程序。
但在动手之前,你必须学习一些基本编程概念。就像魔法师培训,你可能认为这些概念既深奥又啰嗦,但有了一些知识和实践,你就能像魔法师一样指挥你的计算机,完成难以置信的事情。
本章有几个例子,我们鼓励你在交互式环境中输入它们。交互式环境让你每次执行一条Python指令,并立即显示结果。使用交互式环境对于了解基本Python指令的行为是很好的,所以你在阅读时要试一下。做过的事比仅仅读过的内容,更令人印象深刻。
1.1 在交互式环境中输入表达式
启动IDLE就运行了交互式环境,这是和Python一起安装的。在Windows上,打开“开始”菜单,选择“All ProgramsPython 3.3”,然后选择“IDLE(Python GUI)”。在OS X上,选择“ApplicationsMacPython 3.3IDLE”。在Ubuntu上,打开新的终端窗口并输入idle3。
一个窗口会出现,包含>>>提示符,这就是交互式环境。在提示符后输入2 + 2,让Python做一些简单的算术。
>>> 2 + 2
4
IDLE窗口现在应该显示下面这样的文本:
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit
(AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 2 + 2
4
>>>
在Python中,2 + 2称为“表达式”,它是语言中最基本的编程结构。表达式包含“值”(例如2)和“操作符”(例如+),并且总是可以求值(也就是归约)为单个值。这意味着在Python代码中,所有使用表达式的地方,也可以使用一个值。
在前面的例子中,2 + 2被求值为单个值4。没有操作符的单个值也被认为是一个表达式,尽管它求值的结果就是它自己,像下面这样:
>>> 2
2
错误没关系!
如果程序包含计算机不能理解的代码,就会崩溃,这将导致Python显示错误信息。错误信息并不会破坏你的计算机,所以不要害怕犯错误。“崩溃”只是意味着程序意外地停止执行。
如果你希望对一条错误信息了解更多,可以在网上查找这条信息的准确文本,找到关于这个错误的更多内容。也可以查看http://nostarch.com/automatestuff/,这里有常见的Python错误信息和含义的列表。
Python表达式中也可以使用大量其他操作符。例如,表 1-1 列出了Python的所有数学操作符。
表1-1 数学操作符
数学操作符的操作顺序(也称为“优先级”)与数学中类似。**操作符首先求值,接下来是*、/、//和%操作符,从左到右计算。+和-操作符最后求值,也是从左到右计算。如果需要,可以用括号来改变通常的优先级。在交互式环境中输入下列表达式:
>>> 2 + 3 * 6
20
>>> (2 + 3) * 6
30
>>> 48565878 * 578453
28093077826734
>>> 2 ** 8
256
>>> 23 / 7
3.2857142857142856
>>> 23 // 7
3
>>> 23 % 7
2
>>> 2 + 2
4
>>> (5 - 1) * ((7 + 1) / (3 - 1))
16.0
在每个例子中,作为程序员,你必须输入表达式,但Python完成较难的工作,将它求值为单个值。Python将继续求值表达式的各个部分,直到它成为单个值,如图1-1所示。
图1-1 表达式求值将它归约为单个值
将操作符和值放在一起构成表达式的这些规则,是 Python 编程语言的基本部分,就像帮助我们沟通的语法规则一样。下面是例子:
This is a grammatically correct English sentence.
This grammatically is sentence not English correct a.
第二行很难解释,因为它不符合英语的规则。类似地,如果你输入错误的 Python指令,Python也不能理解,就会显示出错误信息,像下面这样:
>>> 5 +File "<stdin>", line 15 +^
SyntaxError: invalid syntax
>>> 42 + 5 + * 2File "<stdin>", line 142 + 5 + * 2^
SyntaxError: invalid syntax
你总是可以在交互式环境中输入一条指令,检查它是否能工作。不要担心会弄坏计算机:最坏的情况就是Python显示出错信息。专业的软件开发者在编写代码时,常常会遇到错误信息。
1.2 整型、浮点型和字符串数据类型
记住,表达式是值和操作符的组合,它们可以通过求值成为单个值。“数据类型”是一类值,每个值都只属于一种数据类型。表1-2列出了Python中最常见的数据类型。例如,值-2和30属于“整型”值。整型(或int)数据类型表明值是整数。带有小数点的数,如3.14,称为“浮点型”(或float)。请注意,尽管42是一个整型,但42.0是一个浮点型。
表1-2 常见数据类型
Python程序也可以有文本值,称为“字符串”,或strs(发音为“stirs”)。总是用单引号(')包围住字符串(例如'Hello'或'Goodbye cruel world!'),这样Python就知道字符串的开始和结束。甚至可以有没有字符的字符串,称为“空字符串”。第4章更详细地解释了字符串。
如果你看到错误信息SyntaxError: EOL while scanning string literal,可能是忘记了字符串末尾的单引号,如下面的例子所示:
>>> 'Hello world!
SyntaxError: EOL while scanning string literal
1.3 字符串连接和复制
根据操作符之后的值的数据类型,操作符的含义可能会改变。例如,在操作两个整型或浮点型值时,+是相加操作符。但是,在用于两个字符串时,它将字符串连接起来,成为“字符串连接”操作符。在交互式环境中输入以下内容:
>>> 'Alice' + 'Bob'
'AliceBob'
该表达式求值为一个新字符串,包含了两个字符串的文本。但是,如果你对一个字符串和一个整型值使用加操作符,Python就不知道如何处理,它将显示一条错误信息。
>>> 'Alice' + 42
Traceback (most recent call last):File "<pyshell#26>", line 1, in <module>'Alice' + 42
TypeError: Can't convert 'int' object to str implicitly
错误信息Can't convert 'int' object to str implicitly表示Python认为,你试图将一个整数连接到字符串'Alice'。代码必须显式地将整数转换为字符串,因为Python不能自动完成转换。(1.6节“程序剖析”在讨论函数时,将解释数据类型转换。)
在用于两个整型或浮点型值时,*操作符表示乘法。但*操作符用于一个字符串值和一个整型值时,它变成了“字符串复制”操作符。在交互式环境中输入一个字符串乘一个数字,看看效果。
>>> 'Alice' * 5
'AliceAliceAliceAliceAlice'
该表达式求值为一个字符串,它将原来的字符串重复若干次,次数就是整型的值。字符串复制是一个有用的技巧,但不像字符串连接那样常用。
*操作符只能用于两个数字(作为乘法),或一个字符串和一个整型(作为字符串复制操作符)。否则,Python将显示错误信息。
>>> 'Alice' * 'Bob'
Traceback (most recent call last):File "<pyshell#32>", line 1, in <module>'Alice' * 'Bob'
TypeError: can't multiply sequence by non-int of type 'str'
>>> 'Alice' * 5.0
Traceback (most recent call last):File "<pyshell#33>", line 1, in <module>'Alice' * 5.0
TypeError: can't multiply sequence by non-int of type 'float'
Python不理解这些表达式是有道理的:你不能把两个单词相乘,也很难将一个任意字符串复制小数次。
1.4 在变量中保存值
“变量”就像计算机内存中的一个盒子,其中可以存放一个值。如果你的程序稍后将用到一个已求值的表达式的结果,就可以将它保存在一个变量中。
1.4.1 赋值语句
用“赋值语句”将值保存在变量中。赋值语句包含一个变量名、一个等号(称为赋值操作符),以及要存储的值。如果输入赋值语句spam = 42,那么名为spam的变量将保存一个整型值42。
可以将变量看成一个带标签的盒子,值放在其中,如图1-2所示。
图1-2 spam = 42 就像是告诉程序“变量spam现在有整数42放在里面”
例如,在交互式环境中输入以下内容:
❶ >>> spam = 40>>> spam40>>> eggs = 2
❷ >>> spam + eggs42>>> spam + eggs + spam82
❸ >>> spam = spam + 2>>> spam42
第一次存入一个值,变量就被“初始化”(或创建)❶。此后,可以在表达式中使用它,以及其他变量和值❷。如果变量被赋了一个新值,老值就被忘记了❸。这就是为什么在例子结束时,spam求值为42,而不是40。这称为“覆写”该变量。在交互式环境中输入以下代码,尝试覆写一个字符串:
>>> spam = 'Hello'
>>> spam
'Hello'
>>> spam = 'Goodbye'
>>> spam
'Goodbye'
就像图1-3中的盒子,这个例子中的spam变量保存了'Hello',直到你用'Goodbye'替代它。
图1-3 如果一个新值赋给变量,老值就被遗忘了
1.4.2 变量名
表1-3中有一些合法变量名的例子。你可以给变量取任何名字,只要它遵守以下3条规则:
1.只能是一个词。
2.只能包含字母、数字和下划线。
3.不能以数字开头。
表1-3 有效和无效的变量名
变量名是区分大小写的。这意味着,spam、 SPAM、Spam和sPaM是4个不同的变量。变量用小写字母开头是Python的惯例。
本书的变量名使用了驼峰形式,没有用下划线。也就是说,变量名用lookLikeThis,而不是looking_like_this。一些有经验的程序员可能会指出,官方的Python代码风格PEP 8,即应该使用下划线。我喜欢驼峰式,这没有错,并认为PEP 8本身“愚蠢的一致性是头脑狭隘人士的心魔”:
“一致地满足风格指南是重要的。但最重要的是,知道何时要不一致,因为有时候风格指南就是不适用。如果有怀疑,请相信自己的最佳判断。”
好的变量名描述了它包含的数据。设想你搬到一间新屋子,搬家纸箱上标的都是“东西”。你永远找不到任何东西!本书的例子和许多Python的文档,使用spam、eggs和bacon等变量名作为一般名称(受到Monty Python的“Spam”短剧的影响),但在你的程序中,具有描述性的名字有助于提高代码可读性。
1.5 第一个程序
虽然交互式环境对于一次运行一条 Python指令很好,但要编写完整的Python程序,就需要在文件编辑器中输入指令。“文件编辑器”类似于Notepad或TextMate这样的文本编辑器,它有一些针对输入源代码的特殊功能。要在IDLE中打开文件编辑器,请选择FileNew ▶File。
出现的窗口中应该包含一个光标,等待你输入,但它与交互式环境不同。在交互式环境中,按下回车,就会执行Python指令。文件编辑器允许输入许多指令,保存为文件,并运行该程序。下面是区别这两者的方法:
- 交互式环境窗口总是有>>>提示符。
- 文件编辑器窗口没有>>>提示符。
现在是创建第一个程序的时候了!在文件编辑器窗口打开后,输入以下内容:
❶ # This program says hello and asks for my name.
❷ print('Hello world!')print('What is your name?') # ask for their name
❸ myName = input()
❹ print('It is good to meet you, ' + myName)
❺ print('The length of your name is:')print(len(myName))
❻ print('What is your age?') # ask for their agemyAge = input()print('You will be ' + str(int(myAge) + 1) + ' in a year.')
在输入完源代码后保存它,这样就不必在每次启动IDLE时重新输入。从文件编辑器窗口顶部的菜单,选择File▶Save As。在“Save As”窗口中,在输入框输入hello.py,然后点击“Save”。
在输入程序时,应该过一段时间就保存你的程序。这样,如果计算机崩溃,或者不小心退出了IDLE,也不会丢失代码。作为快捷键,可以在Windows和Linux上按Ctrl-S,在OS X上按⌘-S,来保存文件。
在保存文件后,让我们来运行程序。选择Run▶Run Module,或按下F5键。程序将在交互式环境窗口中运行,该窗口是首次启动IDLE时出现的。记住,必须在文件编辑器窗口中按F5,而不是在交互式环境窗口中。在程序要求输入时,输入你的名字。在交互式环境中,程序输出应该看起来像这样:
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit
(AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
Hello world!
What is your name?
Al
It is good to meet you, Al
The length of your name is:
2
What is your age?
4
You will be 5 in a year.
>>>
如果没有更多代码行要执行,Python程序就会“中止”。也就是说,它停止运行。(也可以说Python程序“退出”了。)
可以通过点击窗口上部的X,关闭文件编辑器。要重新加载一个保存了的程序,就在菜单中选择File▶Open。现在请这样做,在出现的窗口中选择hello.py,并点击“Open”按钮。前面保存的程序hello.py应该在文件编辑器窗口中打开。
1.6 程序剖析
新程序在文件编辑器中打开后,让我们快速看一看它用到的Python指令,逐一查看每行代码。
1.6.1 注释
下面这行称为“注释”。
❶ # This program says hello and asks for my name.
Python会忽略注释,你可以用它们来写程序注解,或提醒自己代码试图完成的事。这一行中,#标志之后的所有文本都是注释。
有时候,程序员在测试代码时,会在一行代码前面加上#,临时删除它。这称为“注释掉”代码。在你想搞清楚为什么程序不工作时,这样做可能有用。稍后,如果你准备还原这一行代码,可以去掉#。
Python也会忽略注释之后的空行。在程序中,想加入空行时就可以加入。这会让你的代码更容易阅读,就像书中的段落一样。
1.6.2 print()函数
print()函数将括号内的字符串显示在屏幕上。
❷ print('Hello world!')print('What is your name?') # ask for their name
代码行print('Hello world!')表示“打印出字符串'Hello world!'的文本”。Python执行到这行时,你告诉Python调用print()函数,并将字符串“传递”给函数。传递给函数的值称为“参数”。请注意,引号没有打印在屏幕上。它们只是表示字符串的起止,不是字符串的一部分。
也可以用这个函数在屏幕上打印出空行,只要调用print()就可以了,括号内没有任何东西。
在写函数名时,末尾的左右括号表明它是一个函数的名字。这就是为什么在本书中你会看到print(),而不是print。第2章更详细地探讨了函数。
1.6.3 input()函数
函数等待用户在键盘上输入一些文本,并按下回车键。
❸ myName = input()
这个函数求值为一个字符串,即用户输入的文本。前面的代码行将这个字符串赋给变量myName。
你可以认为input()函数调用是一个表达式,它求值为用户输入的任何字符串。如果用户输入'Al',那么该表达式就求值为myName = 'Al'。
1.6.4 打印用户的名字
接下来的print()调用,在括号间包含表达式'It is good to meet you, ' + myName。
❹ print('It is good to meet you, ' + myName)
要记住,表达式总是可以求值为一个值。如果'Al'是上一行代码保存在myName中的值,那么这个表达式就求值为'It is good to meet you, Al'。这个字符串传给print(),它将输出到屏幕上。
1.6.5 len()函数
你可以向len()函数传递一个字符串(或包含字符串的变量),然后该函数求值为一个整型值,即字符串中字符的个数。
❺ print('The length of your name is:')print(len(myName))
在交互式环境中输入以下内容试一试:
>>> len('hello')
5
>>> len('My very energetic monster just scarfed nachos.')
46
>>> len('')
0
就像这些例子,len(myName)求值为一个整数。然后它被传递给print(),在屏幕上显示。请注意,print()允许传入一个整型值或字符串。但如果在交互式环境中输入以下内容,就会报错:
>>> print('I am ' + 29 + ' years old.')
Traceback (most recent call last):File "<pyshell#6>", line 1, in <module>print('I am ' + 29 + ' years old.')
TypeError: Can't convert 'int' object to str implicitly
导致错误的原因不是print()函数,而是你试图传递给print()的表达式。如果在交互式环境中单独输入这个表达式,也会得到同样的错误。
>>> 'I am ' + 29 + ' years old.'
Traceback (most recent call last):File "<pyshell#7>", line 1, in <module>'I am ' + 29 + ' years old.'
TypeError: Can't convert 'int' object to str implicitly
报错是因为,只能用+操作符加两个整数,或连接两个字符串。不能让一个整数和一个字符串相加,因为这不符合Python的语法。可以使用字符串版本的整数,修复这个错误。这在下一节中解释。
1.6.6 str()、int()和float()函数
如果想要连接一个整数(如29)和一个字符串,再传递给print(),就需要获得值'29'。它是29的字符串形式。str()函数可以传入一个整型值,并求值为它的字符串形式,像下面这样:
>>> str(29)
'29'
>>> print('I am ' + str(29) + ' years old.')
I am 29 years old.
因为str(29)求值为’29’,所以表达式'I am ' + str(29) + ' years old.'求值为'I am ' + '29' + ' years old.',它又求值为'I am 29 years old.'。这就是传递给print()函数的值。
str()、int()和float()函数将分别求值为传入值的字符串、整数和浮点数形式。请尝试用这些函数在交互式环境中转换一些值,看看会发生什么。
>>> str(0)
'0'
>>> str(-3.14)
'-3.14'
>>> int('42')
42
>>> int('-99')
-99
>>> int(1.25)
1
>>> int(1.99)
1
>>> float('3.14')
3.14
>>> float(10)
10.0
前面的例子调用了str()、int()和float()函数,向它们传入其他数据类型的值,得到了字符串、整型或浮点型的值。
如果想要将一个整数或浮点数与一个字符串连接,str()函数就很方便。如果你有一些字符串值,希望将它们用于数学运算,int()函数也很有用。例如,input()函数总是返回一个字符串,即便用户输入的是一个数字。在交互式环境中输入spam = input(),在它等待文本时输入101。
>>> spam = input()
101
>>> spam
'101'
保存在spam中的值不是整数101,而是字符串'101'。如果想要用spam中的值进行数学运算,那就用int()函数取得spam的整数形式,然后将这个新值存在spam中。
>>> spam = int(spam)
>>> spam
101
现在你应该能将spam变量作为整数,而不是字符串使用。
>>> spam * 10 / 5
202.0
请注意,如果你将一个不能求值为整数的值传递给int(),Python将显示出错信息。
>>> int('99.99')
Traceback (most recent call last):File "<pyshell#18>", line 1, in <module>int('99.99')
ValueError: invalid literal for int() with base 10: '99.99'
>>> int('twelve')
Traceback (most recent call last):File "<pyshell#19>", line 1, in <module>int('twelve')
ValueError: invalid literal for int() with base 10: 'twelve'
如果需要对浮点数进行取整运算,也可以用int()函数。
>>> int(7.7)
7
>>> int(7.7) + 1
8
在你的程序中,最后3行使用了函数int()和str(),取得适当数据类型的值。
❻ print('What is your age?') # ask for their agemyAge = input()print('You will be ' + str(int(myAge) + 1) + ' in a year.')
myAge变量包含了input()函数返回的值。因为input()函数总是返回一个字符串(即使用户输入的是数字),所以你可以使用int(myAge)返回字符串的整型值。这个整型值随后在表达式int(myAge) + 1中与1相加。
相加的结果传递给str()函数:str(int(myAge) + 1)。然后,返回的字符串与字符串'You will be '和' in a year.'连接,求值为一个更长的字符串。这个更长的字符串最终传递给print(),在屏幕上显示。
假定用户输入字符串'4',保存在myAge中。字符串'4'被转换为一个整型,所以你可以对它加1。结果是5。str()函数将这个结果转化为字符串,这样你就可以将它与第二个字符串'in a year.'连接,创建最终的消息。这些求值步骤如图1-4所示。
文本和数字相等判断
虽然数字的字符串值被认为与整型值和浮点型值完全不同,但整型值可以与浮点值相等。
>>> 42 == '42'
False
>>> 42 == 42.0
True
>>> 42.0 == 0042.000
True
Python进行这种区分,因为字符串是文本,而整型值和浮点型都是数字。
图1-4 如果4保存在myAge中,求值的步骤
1.7 小结
你可以用一个计算器来计算表达式,或在文本处理器中输入字符串连接。甚至可以通过复制粘贴文本,很容易地实现字符串复制。但是表达式以及组成它们的值(操作符、变量和函数调用),才是构成程序的基本构建块。一旦你知道如何处理这些元素,就能够用Python操作大量的数据。
最好是记住本章中介绍的不同类型的操作符(+、-、*、/、//、%和**是数学操作符,+和*是字符串操作符),以及3种数据类型(整型、浮点型和字符串)。
我们还介绍了几个不同的函数。print()和input()函数处理简单的文本输出(到屏幕)和输入(通过键盘)。len()函数接受一个字符串,并求值为该字符串中字符的数目。
在下一章中,你将学习如何告诉Python根据它拥有的值,明智地决定什么代码要运行,什么代码要跳过,什么代码要重复。这称为“控制流”,它让你编写程序来做出明智的决定。