1. Python 入门指南
Python 是一门简单易学且功能强大的编程语言。它拥有高效的高级数据结构,并且能够用简单而又高效的方式进行面向对象编程。Python 优雅的语法和动态类型,再结合它的解释性,使其在大多数平台的许多领域中成为编写脚本或开发应用程序的理想语言。
你可以自由的从 Python 官方点: http://www.python.org,以源代码或二进制形式获取 Python 解释器及其标准扩展库,并可以自由的分发。此站点同时也提供了大量的第三方 Python 模块、程序和工具,及其附加文档。
你可以很容易的使用 C 或 C++(其它可以通过 C 调用的语言)为 Python 解释器扩展新函数和数据类型。 Python 还可以被用作定制应用程序的一门扩展语言。
本手册非正式的向读者介绍了 Python 语言及其体系相关的基本知识与概念。在学习实践中结合使用 Python 解释器是很有帮助的,不过所有的例子都是完整的,所以本手册亦可离线阅读。
如果需要了解相关标准库或对象的详细介绍,请查阅 Python 参考文档 。Python 参考手册 提供了更多语言相关的正式说明。如果想要使用 C 或 C++ 编写扩展,请查阅 Python 解释器扩展和集成章节 和 C API 参考手册 。当然也可阅读一些深入介绍 Python 知识的书籍。
本手册不会尝试涵盖 Python 的全部知识和每个特性,甚至不会涵盖所有常用的特性。相反的,它介绍了 Python 中许多最引人瞩目的特性,并且会给你一个关于语言特色和风格的认识。 读完之后,你将能够阅读和编写 Python 模块或程序,并为以后使用 Python 参考手册 继续学习诸多 Python 模块库做好准备。
1. 开胃菜
如果你要用计算机做很多工作,最后你会发现有一些任务你更希望用自动化的方式进行处理。 比如,你想要在大量的文本文件中执行查找/替换,或者以复杂的方式对大量的图片进行重命名和整理。 也许你想要编写一个小型的自定义数据库、一个特殊的 GUI 应用程序或一个简单的小游戏。
如果你是一名专业的软件开发者,可能你必须使用几种 C/C++/java 类库,并且发现通常编写/编译/测试/重新编译的周期是如此漫长。 也许你正在为这些类库编写测试用例,但是发现这是一个让人烦躁的工作。 又或者你已经完成了一个可以使用扩展语言的程序,但你并不想为此重新设计并实现一套全新的语言。
那么 Python 正是你所需要的语言。
虽然你能够通过编写 Unix shell 脚本或 Windows 批处理文件来处理其中的某些任务,但 Shell 脚本更适合移动文件或修改文本数据,并不适合编写 GUI 应用程序或游戏;虽然你能够使用 C/C++/JAVA 编写程序,但即使编写一个简单的 first-draft 程序也有可能耗费大量的开发时间。相比之下,Python 更易于使用,无论在 Windows、Mac OS X 或 Unix 操作系统上它都会帮助你更快地完成任务。
虽然 Python 易于使用,但它却是一门完整的编程语言;与 Shell 脚本或批处理文件相比,它为编写大型程序提供了更多的结构和支持。另一方面,Python 提供了比 C 更多的错误检查,并且作为一门 高级语言 ,它内置支持高级的数据结构类型,例如:灵活的数组和字典。因其具有更多的通用数据类型,同 Awk 甚至 Perl 相比较,Python 适用于更多领域,至少大多数事情在 Python 中与其他语言同样简单。
Python 允许你将程序分割为不同的模块,以便在其他的 Python 程序中重用。Python 内置提供了大量的标准模块,你可以将其用作程序的基础,或者作为学习 Python 编程的示例。 这些模块提供了诸如文件 I/O、系统调用、Socket 支持,甚至类似 Tk 的用户图形界面(GUI)工具包接口。
Python 是一门解释型语言,因为无需编译和链接,你可以在程序开发中节省宝贵的时间。Python 解释器可以交互地使用,这使得试验语言的特性、编写临时程序或在自底向上的程序开发中测试方法非常容易。 你甚至还可以把它当做一个桌面计算器。
Python 让程序编写的紧凑和可读。用 Python 编写的程序通常比同样的 C、C++ 或 Java 程序更短小,这是因为以下几个原因:
高级数据结构使你可以在一条语句中表达复杂的操作;
语句组使用缩进代替开始和结束大括号来组织;
变量或参数无需声明。
Python 是 可扩展 的:如果你会 C 语言编程便可以轻易的为解释器添加内置函数或模块,或者为了对性能瓶颈作优化,或者将 Python 程序与只有二进制形式的库(比如某个专业的商业图形库)连接起来。一旦你真正掌握了它,你可以将 Python 解释器集成进某个 C 应用程序,并把它当作那个程序的扩展或命令行语言。
顺便说一句,这个语言的名字来自于 BBC 的 “Monty Python’s Flying Cirecus” 节目,和爬行类动物没有任何关系。在文档中引用 Monty Python 的典故不仅可行,而且值得鼓励!
现在你已经为 Python 兴奋不已了吧,迫不及待地想要领略更多的细节! 学习一门语言最好的方法就是使用它,本指南推荐你边读边使用 Python 解释器练习。
下一节中,我们将解释 Python 解释器的用法。这是很简单的一件事情,但它有助于试验后面的例子。
本手册剩下的部分将通过示例介绍 Python 语言及系统的诸多特性,开始是简单的语法、数据类型和表达式,接着介绍函数与模块,最后涉及异常和自定义类这样的高级内容。
4. 深入 Python 流程控制
4.1. if 语句
也许最有名的是 if 语句。例如:
>>> x = int(raw_input("Please enter an integer: "))Please enter an integer: 42>>> if x < 0:... x = 0... print 'Negative changed to zero'... elif x == 0:... print 'Zero'... elif x == 1:... print 'Single'... else:... print 'More'...More
可能会有零到多个 elif 部分,else 是可选的。关键字 elif 是 “else if” 的缩写,这个可以有效避免过深的缩进。if ... elif ... elif ... 序列用于替代其它语言中的 switch
或 case
语句。
4.2. for 语句
Python 中的 for 语句和 C 或 Pascal 中的略有不同。通常的循环可能会依据一个等差数值步进过程(如 Pascal),或由用户来定义迭代步骤和中止条件(如 C ),Python 的 for 语句依据任意序列(链表或字符串)中的子项,按它们在序列中的顺序来进行迭代。例如(没有暗指):
>>> # Measure some strings:... words = ['cat', 'window', 'defenestrate']>>> for w in words:... print w, len(w)...cat 3window 6defenestrate 12
在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)。如果你想要修改你迭代的序列(例如:复制选择项),你可以迭代它的复本。使用切割标识就可以很方便地做到这一点:
>>> for w in words[:]: # Loop over a slice copy of the entire list.... if len(w) > 6:... words.insert(0, w)...>>> words['defenestrate', 'cat', 'window', 'defenestrate']
4.3. range() 函数
如果你需要一个数值序列,内置函数 range() 会很方便,它生成一个等差级数链表:
>>> range(10)[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(10)
生成了一个包含 10 个值的链表,它用链表的索引值填充了这个长度为 10 的列表,所生成的链表中不包括范围中的结束值。也可以让 range 操作从另一个数值开始,或者可以指定一个不同的步进值(甚至是负数,有时这也被称为 “步长”):
>>> range(5, 10)[5, 6, 7, 8, 9]>>> range(0, 10, 3)[0, 3, 6, 9]>>> range(-10, -100, -30)[-10, -40, -70]
需要迭代链表索引的话,如下所示结合使用 range() 和 len():
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']>>> for i in range(len(a)):... print i, a[i]...0 Mary1 had2 a3 little4 lamb
不过,这种场合可以方便地使用 enumerate(),请参见 循环技巧。
4.4. break 和 continue 语句, 以及循环中的 else 子句
break 语句和 C 中的类似,用于跳出最近的一级 for 或 while 循环。
循环可以有一个 else
子句;它在循环迭代完整个列表 (对于 for) 后或执行条件为 false (对于 while) 时执行,但循环被 break 中止的情况下不会执行。以下搜索素数的示例程序演示了这个子句:
>>> for n in range(2, 10):... for x in range(2, n):... if n % x == 0:... print n, 'equals', x, '*', n/x... break... else:... # loop fell through without finding a factor... print n, 'is a prime number'...2 is a prime number3 is a prime number4 equals 2 * 25 is a prime number6 equals 2 * 37 is a prime number8 equals 2 * 49 equals 3 * 3
(Yes, 这是正确的代码。看仔细: else
语句是属于 for 循环之中, 不是 if 语句。)
与循环一起使用时,else
子句与 try 语句的 else
子句比与 if 语句的具有更多的共同点:try 语句的 else
子句在未出现异常时运行,循环的 else
子句在未出现 break
时运行。更多关于 try 语句和异常的内容,请参见 异常处理。
continue 语句是从 C 中借鉴来的,它表示循环继续执行下一次迭代:
>>> for num in range(2, 10):... if num % 2 == 0:... print "Found an even number", num... continue... print "Found a number", numFound an even number 2Found a number 3Found an even number 4Found a number 5Found an even number 6Found a number 7Found an even number 8Found a number 9
4.5. pass 语句
pass 语句什么也不做。它用于那些语法上必须要有什么语句,但程序什么也不做的场合,例如:
>>> while True:... pass # Busy-wait for keyboard interrupt (Ctrl+C)...
这通常用于创建最小结构的类:
>>> class MyEmptyClass:... pass...
另一方面,pass 可以在创建新代码时用来做函数或控制体的占位符。可以让你在更抽象的级别上思考。pass 可以默默地被忽视:
>>> def initlog(*args):... pass # Remember to implement this!...
4.6. 定义函数
我们可以定义一个函数用来生成任意上界的菲波那契数列:
>>> def fib(n): # write Fibonacci series up to n... """Print a Fibonacci series up to n."""... a, b = 0, 1... while a < n:... print a,... a, b = b, a+b...>>> # Now call the function we just defined:... fib(2000)0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键字 def 引入了一个函数 定义 。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须是缩进的。
函数体的第一行语句可以是可选的字符串文本,这个字符串是函数的文档字符串,或者称为 docstring 。(更多关于 docstrings 的信息请参考 文档字符串 ) 有些工具通过 docstrings 自动生成在线的或可打印的文档,或者让用户通过代码交互浏览;在你的代码中包含 docstrings 是一个好的实践,让它成为习惯吧。
函数 调用 会为函数局部变量生成一个新的符号表。确切地说,所有函数中的变量赋值都是将值存储在局部符号表。变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值 (除非用 global 语句命名),尽管他们可以被引用。
函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是 传值调用 (这里的 值 总是一个对象引用,而不是该对象的值)。[1] 一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建。
一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)存在一个被 Python 解释器认定为 用户自定义函数 的类型。这个值可以赋予其他的名字(即变量名),然后它也可以被当做函数使用。这可以作为通用的重命名机制:
>>> fib<function fib at 10042ed0>>>> f = fib>>> f(100)0 1 1 2 3 5 8 13 21 34 55 89
如果你使用过其他语言,你可能会反对说:fib
不是一个函数,而是一个方法,因为它并不返回任何值。事实上,没有 return 语句的函数确实会返回一个值,虽然是一个相当令人厌烦的值(指 None )。这个值被称为 None
(这是一个内建名称)。如果 None
值是唯一被书写的值,那么在写的时候通常会被解释器忽略(即不输出任何内容)。如果你确实想看到这个值的输出内容,请使用 print:
>>> fib(0)>>> print fib(0)None
以下示例演示了如何从函数中返回一个包含菲波那契数列的数值链表,而不是打印它:
>>> def fib2(n): # return Fibonacci series up to n... """Return a list containing the Fibonacci series up to n."""... result = []... a, b = 0, 1... while a < n:... result.append(a) # see below... a, b = b, a+b... return result...>>> f100 = fib2(100) # call it>>> f100 # write the result[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
和以前一样,这个例子演示了一些新的 Python 功能:
return 语句从函数中返回一个值。
不带表达式的 return 返回
None
。过程结束后也会返回None
。语句
result.append(b)
称为链表对象result
的一个 方法 (method)。方法是一个“属于”某个对象的函数,它被命名为
obj.methodename
,这里的obj
是某个对象(可能是一个表达式),methodename
是某个在该对象类型定义中的方法的命名。不同的类型定义不同的方法。不同类型可能有同样名字的方法,但不会混淆(当你定义自己的对象类型和方法时,可能会出现这种情况,class 的定义方法详见 类 )。示例中演示的append()
方法由链表对象定义,它向链表中加入一个新元素。在示例中它等同于result = result + [b]
,不过效率更高。
4.7. 深入 Python 函数定义
在 Python 中,你也可以定义包含若干参数的函数。这里有三种可用的形式,也可以混合使用。
4.7.1. 默认参数值
最常用的一种形式是为一个或多个参数指定默认值。这会创建一个可以使用比定义时允许的参数更少的参数调用的函数,例如:
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
while True:
ok = raw_input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise IOError('refusenik user')
print complaint
这个函数可以通过几种不同的方式调用:
只给出必要的参数:
ask_ok('Do you really want to quit?')
给出一个可选的参数:
ask_ok('OK to overwrite the file?', 2)
或者给出所有的参数:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
这个例子还介绍了 in 关键字。它测定序列中是否包含某个确定的值。
默认值在函数 定义 作用域被解析,如下所示:
i = 5def f(arg=i):
print argi = 6f()
将会输出 5
。
重要警告: 默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数:
def f(a, L=[]):
L.append(a)
return Lprint f(1)print f(2)print f(3)
这将会打印:
[1][1, 2][1, 2, 3]
如果你不想在随后的调用中共享默认值,可以像这样写函数:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
4.7.2. 关键字参数
函数可以通过 关键字参数 的形式来调用,形如 keyword = value
。例如,以下的函数:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print "-- This parrot wouldn't", action,
print "if you put", voltage, "volts through it."
print "-- Lovely plumage, the", type
print "-- It's", state, "!"
接受一个必选参数( voltage
)以及三个可选参数( state
, action
, 和 type
)。可以用以下的任一方法调用:
parrot(1000) # 1 positional argumentparrot(voltage=1000) # 1 keyword argumentparrot(voltage=1000000, action='VOOOOOM') # 2 keyword argumentsparrot(action='VOOOOOM', voltage=1000000) # 2 keyword argumentsparrot('a million', 'bereft of life', 'jump') # 3 positional argumentsparrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
不过以下几种调用是无效的:
parrot() # required argument missingparrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argumentparrot(110, voltage=220) # duplicate value for the same argumentparrot(actor='John Cleese') # unknown keyword argument
在函数调用中,关键字的参数必须跟随在位置参数的后面。传递的所有关键字参数必须与函数接受的某个参数相匹配(例如 actor
不是 parrot
函数的有效参数),它们的顺序并不重要。这也包括非可选参数(例如 parrot(voltage=1000)
也是有效的)。任何参数都不可以多次赋值。下面的示例由于这种限制将失败:
>>> def function(a):... pass...>>> function(0, a=0)Traceback (most recent call last):
File "<stdin>", line 1, in ?TypeError: function() got multiple values for keyword argument 'a'
引入一个形如 **name
的参数时,它接收一个字典(参见 Mapping Types — dict ),该字典包含了所有未出现在形式参数列表中的关键字参数。这里可能还会组合使用一个形如 *name
(下一小节详细介绍)的形式参数,它接收一个元组(下一节中会详细介绍),包含了所有没有出现在形式参数列表中的参数值。( *name
必须在 **name
之前出现)例如,我们这样定义一个函数:
def cheeseshop(kind, *arguments, **keywords):
print "-- Do you have any", kind, "?"
print "-- I'm sorry, we're all out of", kind
for arg in arguments:
print arg
print "-" * 40
keys = sorted(keywords.keys())
for kw in keys:
print kw, ":", keywords[kw]
它可以像这样调用:
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper='Michael Palin',
client="John Cleese",
sketch="Cheese Shop Sketch")
当然它会按如下内容打印:
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
注意在打印关键字参数之前,通过对关键字字典 keys()
方法的结果进行排序,生成了关键字参数名的列表;如果不这样做,打印出来的参数的顺序是未定义的。
4.7.3. 可变参数列表
最后,一个最不常用的选择是可以让函数调用可变个数的参数。这些参数被包装进一个元组(参见 元组和序列 )。在这些可变个数的参数之前,可以有零到多个普通的参数:
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
4.7.4. 参数列表的分拆
另有一种相反的情况: 当你要传递的参数已经是一个列表,但要调用的函数却接受分开一个个的参数值。这时候你要把已有的列表拆开来。例如内建函数 range() 需要独立的 start ,stop 参数。 你可以在调用函数时加一个 *
操作符来自动把参数列表拆开:
>>> list(range(3, 6)) # normal call with separate arguments[3, 4, 5]>>> args = [3, 6]>>> list(range(*args)) # call with arguments unpacked from a list[3, 4, 5]
以同样的方式,可以使用 **
操作符分拆关键字参数为字典:
>>> def parrot(voltage, state='a stiff', action='voom'):... print "-- This parrot wouldn't", action,... print "if you put", voltage, "volts through it.",... print "E's", state, "!"...>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}>>> parrot(**d)-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
4.7.5. Lambda 形式
出于实际需要,有几种通常在函数式编程语言例如 Lisp 中出现的功能加入到了 Python 中。通过 lambda 关键字,可以创建短小的匿名函数。这里有一个函数返回它的两个参数的和:lambda a, b: a+b
。Lambda 形式可以用于任何需要的函数对象。出于语法限制,它们只能有一个单独的表达式。语义上讲,它们只是普通函数定义中的一个语法技巧。类似于嵌套函数定义,lambda 形式可以从外部作用域引用变量:
>>> def make_incrementor(n):... return lambda x: x + n...>>> f = make_incrementor(42)>>> f(0)42>>> f(1)43
上面的示例使用 lambda 表达式返回一个函数。另一个用途是将一个小函数作为参数传递:
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]>>> pairs.sort(key=lambda pair: pair[1])>>> pairs[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
4.7.6. 文档字符串
这里介绍的文档字符串的概念和格式。
第一行应该是关于对象用途的简介。简短起见,不用明确的陈述对象名或类型,因为它们可以从别的途径了解到(除非这个名字碰巧就是描述这个函数操作的动词)。这一行应该以大写字母开头,以句号结尾。
如果文档字符串有多行,第二行应该空出来,与接下来的详细描述明确分隔。接下来的文档应该有一或多段描述对象的调用约定、边界效应等。
Python 的解释器不会从多行的文档字符串中去除缩进,所以必要的时候应当自己清除缩进。这符合通常的习惯。第一行之后的第一个非空行决定了整个文档的缩进格式。(我们不用第一行是因为它通常紧靠着起始的引号,缩进格式显示的不清楚)留白”相当于”是字符串的起始缩进。每一行都不应该有缩进,如果有缩进的话,所有的留白都应该清除掉。留白的长度应当等于扩展制表符的宽度(通常是8个空格)。
以下是一个多行文档字符串的示例:
>>> def my_function():... """Do nothing, but document it....... No, really, it doesn't do anything.... """... pass...>>> print my_function.__doc__ Do nothing, but document it. No, really, it doesn't do anything.
4.8. 插曲:编码风格
此时你已经可以写一个更长更复杂的 Python 程序,是时候讨论一下 编码风格 了。大多数语言可以写 (或者更明白地说,格式化 ) 作几种不同的风格。有些比其它的更好读。让你的代码对别人更易读是个好想法,养成良好的编码风格对此很有帮助。
对于 Python, PEP 8 引入了大多数项目遵循的风格指导。它给出了一个高度可读,视觉友好的编码风格。每个 Python 开发者都应该读一下,大多数要点都会对你有帮助:
使用 4 空格缩进,而非 TAB。
在小缩进(可以嵌套更深)和大缩进(更易读)之间,4 空格是一个很好的折中。TAB 引发了一些混乱,最好弃用。
折行以确保其不会超过 79 个字符。
这有助于小显示器用户阅读,也可以让大显示器能并排显示几个代码文件。
使用空行分隔函数和类,以及函数中的大块代码。
可能的话,注释独占一行
使用文档字符串
把空格放到操作符两边,以及逗号后面,但是括号里侧不加空格:
a = f(1, 2) + g(3, 4)
。统一函数和类命名。
推荐类名用
驼峰命名
,函数和方法名用小写_和_下划线
。总是用self
作为方法的第一个参数(关于类和方法的知识详见 初识类)。不要使用花哨的编码,如果你的代码的目的是要在国际化 环境。Python 的默认情况下,UTF-8,甚至普通的 ASCII 总是工作的最好。
同样,也不要使用非 ASCII 字符的标识符,除非是不同语种的会阅读或者维护代码。
Footnotes
扫描二维码推送至手机访问。
版权声明:本文章来源于网络,版权归原作者所有,如果本站文章侵犯了您的权益,请联系我们删除,联系邮箱:luxd@aliyun.com,感谢支持理解。