- 论坛徽章:
- 0
|
转贴一篇不错的Python入门教程 - Instant Hacking[译文]
原文 http://www.hetland.org/python/instant-hacking.php
Instant Hacking[译文]
译者: 肯定来过
这是一篇简短的关于python程序设计语言的入门教程,原文在这里,翻着词典翻译了来!
这是一份对编程艺术的简短介绍,其中的例子是用python写成的。(如果你已经知道了该如何编程,但是想简单了解一下python,你可以查阅我的另一篇文章Instant Python。)这篇文章已经被翻译为意大利、波兰、日本、塞尔维亚以及巴西葡萄亚语等许多种语言,而且正在被翻译为韩语。(译者:当然,现在已经包括了中文版本,只是作者并不知道。)
这篇文章和如何闯入别人的计算机系统之类的东西无关。我不关注那类事情,所以请不要email问我那些东西。
注意:要使此文中的例子正确运行,你应该把它们写在一个文本文件中,然后用解释器运行;不要试图直接在交互方式下运行它们--不是所有的都可以这样运行。(不要问我和此有关的具体细节。最好查阅python文档或者email给help@python.org)。
1. 运行环境
要用python写程序,你必须先安装一个python的解释器。它可以存在于大多数平台(包括Macintosh、Unix和Windows)。更多与此有关的信息可以在python的网站上找到。你还应该有一个文本编辑器(象emacs、notepad或者类似的东西)。
2. 编程是什么?
为计算机写程序其实就是给它一系列的指令告诉它去做什么。计算机程序在某些方面就象是菜谱,指导我们如何做菜的那种。例如[1]:
假日火腿沙拉
原料:
腌泡汁:
1/4杯酸橙汁
1/4杯低钠大豆酱油
1/4杯水
1大汤匙植物油
3/4茶匙小茴香
1/2茶匙牛至
1/4茶匙热胡椒粉
2片丁香、大蒜,捣碎
沙拉:
1份(12盎司)罐装少钠午餐肉火腿切成条状
1个洋葱,切片
胡椒粉,切好的生菜
12个樱桃西红柿,切半
方法:
把腌泡汁装在有合适盖子的广口瓶里摇匀。用塑料袋装上火腿,泼上腌泡汁,封住袋口。在电冰箱里腌制30分钟。从塑料袋里取出火腿;准备2大汤匙腌泡汁,在煮锅里煮一下。加上火腿、洋葱、绿色的胡椒。烧3到4分钟直到火腿熟了为止……
当然,没有一台计算机会懂这个……而且即便是懂,大多数计算机也不可能烧制出一份沙拉。那么,我们该如何让这些变得对计算机来说更为友好一些呢?从根本上说依赖于两点:首先,我们必须以计算机可以理解的方式与之交流;其次还要和它谈论它能够做到的事情。
第一点意味着我们必须使用一种语言--一种已经为之准备好了解释器的程序设计语言,第二点意味着我们不能期望计算机为我们做一份沙拉--但是我们可以让它做数字累加或者在屏幕上打印东西之类的事情。
3. Hello……
程序设计教程有一个传统,通常以在屏幕上打印“Hello, world!”这样的程序做为开始。对python来说,这非常简单:
它从根本上说很象上面的菜谱(尽管要短得多!)。它告诉计算机做什么:打印“Hello, world!”。如果让它打印更多的废话该怎么做呢?很简单:
- print "Hello, world!"
- print "Goodbye, world!"
复制代码
不比上一个难,是不是?但是不怎么有趣……我们希望它可以处理更多的元素,就象沙拉菜谱那样。那么,我们都有哪些元素呢?首先,有字符串,象“Hello, world!”,除此之外还有数字。假设我们打算让计算机为我们计算矩形的面积。我们可以给它如下的菜谱:
- # The Area of a Rectangle
- # Ingredients:
- width = 20
- height = 30
- # Instructions:
- area = width * height
- print area
复制代码
你大概可以看出它同火腿沙拉菜谱的相似性(尽管有些细微的差别)。但它是如何工作的呢?首先,以#开始的行叫做注释事实上会被计算机忽略。然而插入象这样小段的注释对于增强你程序的可读性来说是很重要的。
接下来,看起来象 foo = bar 这样的行叫做赋值。对于 width = 20 这样的情况来说就是告诉计算机从这里开始width就代表20了。它还意味着一个名字为“width”的变量从此被创建了(如果它先前已经存在,那么会被重新覆盖)。所以,我们以后使用这个变量的时候,计算机就知道了它的值。因此,
width * height
本质上同
20 * 30
一样会计算出600这个结果,然后赋给名称为“area”的变量。程序的最后一句在屏幕上打印出变量“area”的值,所以你看到这个程序运行的最终结果仅仅是
600
注意:在某些程序设计语言中,你必须在程序开始的时候告诉计算机你将会用到哪些变量(就象沙拉中的元素)--而python足够聪明,所以你可以根据需要随时创建。
4. 反馈
现在,你可以执行一些简单,或者再复杂一点的计算了。比方说,你或许打算写一段程序来计算圆形的面积而不是矩形的:
- radius = 30
- print radius * radius * 3.14
复制代码
然而,这事实上并不比计算矩形面积的那个程序更有意思。至少在我看来是这样。它有些僵硬。如果我们看到半径为31的圆该怎么办?怎样让计算机知道?这有点象沙拉菜谱中的:“烧3到4分钟直到火腿熟了为止。”要知道何时烧熟,我们必须检查。我们需要反馈,或者提示。计算机如何知道我们圆形的半径?同样需要输入资料……我们可以做的是告诉计算机半径是多少:
- radius = input("What is the radius?")
- print radius * radius * 3.14
复制代码
现在程序变得漂亮一些了……input是个被称为函数的东西。(很快你将学习创建你自己的函数。而input是python内建的函数。)仅仅写下
input
什么也不会做……你必须在它的后面放上一对括号。所以input()可以工作--它会简单的要求用户输入半径的长度。而上面的那个版本对用户来说也许更友好一些,因为它首先打印出了一个问题。当我们将诸如提问字符串“What is the radius?”之类的东西放在函数调用的括号中时,这个过程被称为函数的参数传递。括号中的内容被称为参数。在上个例子中我们传递了一个提问作为参数以便input知道在获得答案前应该先打印什么。
但是获得的答案如何到达radius变量呢?函数input,调用时,会返回一个值(象许多其它函数一样)。你不一定非要使用这个值,但象我们这种情况,我们要使用它。这样,下面这两个表达式有着很大的差别:
- foo = input
- bar = input()
复制代码
foo现在包含input函数本身(所以它事实上可以象foo("What is your age?" 这样使用;这被称为动态函数调用)而bar包含用户键入的值。
5. 流程
现在我们可以编写程序执行简单的任务(运算和打印)并且可以获得用户输入了。这很有用,但仍然局限在按顺序执行命令,也就是说--它们必须按照事先安排好的顺序执行。大多数火腿沙拉菜谱是象这样顺序或者线性叙述的。但是如果我们打算让计算机检查沙拉是否烧好该怎样告诉它呢?如果烧好了,那么应该从烘箱里把它取出来--否则的话,应该接着让它烧更长一段时间什么的。我们如何表达这个?
我们想做的,其实是控制程序的流程。它可以从两个方向执行--要么拿开火腿,要不继续让它留在烘箱里。我们可以选择,条件是它是否烧好。这被称为条件执行。我们可以这样写:
- temperature = input("What is the temperature of the spam?")
- if temperature >; 50:
- print "The salad is properly cooked."
- else:
- print "Cook the salad some more."
复制代码
意思很明显:如果温度超过50(摄氏度),那么打印出信息告诉用户烧好了,否则,告诉用户再烧制一段时间。
注意:缩进在python中很重要。条件执行(还有循环执行以及函数定义--见后面)中的语句块必须被缩进(而且要缩进同等数量的空格;一个键相当于8个空格)以便解释器可以知道它们从哪里开始到哪里结束。这同时也使程序变得更加可读。
让我们回到先前的面积计算问题。能看出来这段程序做什么吗?
- # Area calculation program
- print "Welcome to the Area calculation program"
- print "---------------------------------------"
- print
- # Print out the menu:
- print "Please select a shape:"
- print "1 Rectangle"
- print "2 Circle"
- #Get the user's choice:
- shape = input(">; ")
- #Calculate the area:
- if shape == 1:
- height = input("Please enter the height: ")
- width = input("Please enter the width: ")
- area = height *width
- print "The area is ", area
- else:
- radius = input("Please enter the radius: ")
- area = 3.14 * (radius**2)
- print "The area is ", area
复制代码
这个例子中的新东西:
1. 只使用print本身将打印出一个空行
2. ==检查两个值是否相等,与=不同,后者把表达式右侧的值赋给左侧的变量。这是一个非常重要的差别!
3. **是python的幂运算符--因此半径的平方被写成radius**2
4. print能够打印出不止一个东西。只要用逗号把它们分开就可以了。(它们在输出时会用单个空格分开。)
这个程序很简单:它要一个数字,告诉它用户打算让它计算矩形或是圆形的面积。然后,使用一个if语句(条件执行)来决定应当执行哪个语句块计算面积。这两个语句块同先前面积计算例子中使用的语句块本质上是一样的。留意注释是如何使代码变得更加可读的。编程的第一条戒律就是:“你应当注释!”无论如何--它都是一个应该养成的好习惯。
练习1:
扩展上面的程序使它包括正方形面积的计算,用户只要输入它一条边的长度就可以了。做这个练习之前你需要了解一件事:如果你有两个以上的选择,你可以象这样写:
- if foo == 1:
- # Do something...
- elif foo == 2:
- # Do something else...
- elif foo == 3:
- # If all else fails...
复制代码
这里的elif是意思为“else if”的神秘代码 。所以,如foo等于1,做某件事;否则,如果foo等于2,那么做另外的一些事,等等。你也可以在程序中加入其它的选项--象三角形以及任意多边形。随你的便。
6. 循环
顺序执行和条件执行仅仅是程序设计三个基本语句块架构方式中的两个。第三个则是循环执行。在上个段落中我假设了一种情况,检查火腿是否烧好,但很明显它并不适用。如果下次检查时火腿仍然没烧好该怎么办?我们怎么知道需要检查多少次?事实上,我们不知道。而且我们也没必要知道。我们可以要求计算机持续检查直到烧好了为止。怎么表达这个?你猜到了--我们使用循环,或者说是重复执行。
python有两种循环类型:while循环和for循环。for循环大概是最简单的。举个例子:
- for food in "spam", "eggs", "tomatoes":
- print "I love", food
复制代码
它的意思是:对于列表"spam", "eggs", "tomatoes"中的每个元素,都打印出你喜欢它。循环中的语句块为每个元素执行一次,而且每次执行,当前的元素都被赋给变量food(在这个例子中)。另外一个例子:
- for number in range(1, 100):
- print "Hello, world!"
- print "Just", 100 - number, "more to go..."
- print "Hello, world"
- print "That was the last one... Phew!"
复制代码
函数range返回给定范围的数字列表(包括第一个数字,不包括最后一个……这个例子中是[1……99])。所以,这样解释它:
循环体为1(包括)到100(不包括)之间的数字每个执行一次。(哪个是循环体以及随后的表达式事实上做什么留下来做为练习。)
但这对我们的烧菜问题并没有实质的帮助。如果我们打算检查火腿一百次,那么这是个很好的解决方案;但是我们不知道这是否够--或者太多了。我们只是希望它在温度达不到(或者,直到它足够热--大致某个状态)的时候持续检查。所以,我们使用while:
- # Spam-cooking program
- # Fetch the function sleep
- from time import sleep
- print "Please start cooking the spam. (I'll be back in 3 minutes.)"
- # Wait for 3 minutes (that is, 3*60 seconds)...
- sleep(180)
- print "I'm baaack :)"
- # How hot is hot enough?
- hot_enough = 50
- temperature = input("How hot is the spam?")
- while temperature < hot_enouth:
- print "Not hot enough... Cook it a bit more..."
- sleep(30)
- temperature = input("OK, How hot is it now?")
- print "It's hot enough - You're done!"
复制代码
这个例子中的新东西……
1. 有些有用的函数被存储在模块中而且可以被导入。此例中我们从python自带的time模块中导入了函数sleep(它休止给定的多少秒的时间)。(做你自己的模块当然也是可能的……)
练习2:
写一个程序,持续从用户获得数据然后相加,直到它们的和为100。再写一个程序,从用户那里获得100个数据,打印出它们的和。
Bigger Programs - Abstraction
如果想知道一本书的大致内容,你不会翻遍所有的页--你只是看看目录,是不是?它会列出书的主要内容。现在--想像写一本菜谱。许多菜谱,像“奶油火腿通心面”和“瑞士火腿馅饼”很可能包含相同的东西,比如火腿,在这种情况下--你肯定不会打算在每个菜谱里都重复叙述如何制作火腿。(好了……你事实上可能不做火腿……但是为了做例子,请忍受一下 )。你会把制作火腿的菜谱单独放在一个章节,而仅仅在其它章节里引用它。这样--代替在每个菜谱里都完整的描述,你只要引用章节的名称就可以了。在计算机编程中这被称为抽象化。
我们是不是已经象这样运行了某些东西?是的。我们没有详细的告诉计算机如何从用户那里获得一个答案(好了--我们没有真的这样做……同样地……我们也没有真正的在做火腿 )而是简单的使用了input--一个函数来代替。我们事实上可以构造我们自己的函数,来应用于这种类型的抽象化中。
假设我们希望找到小于给定正数的最大整数。例如,给定2.7,这个数应当是2。这往往被称为给定数的“底线(floor)”。(这事实上可以用python的内建函数int来处理,但是,请再次忍受我拿它作例子……)我们该怎样做?一个简单的解决办法是从0开始试每一个可能的数:
- number = input("What is the number?")
- floor = 0
- while floor <= number:
- floor = floor + 1
- floor = floor - 1
- print "The floor of ", number, "is ", floor
复制代码
注意当floor不再小于(或者等于)给定数时循环结束了;我们加了太多1给它。因此我们必须为它减去1。如果我们希望把它应用于完整的数学运算该怎么办呢?我们不得不为求每个数的基数("floor"-ing)而写一次完整的循环。这很不舒服……你可能猜到了我们代之以什么:把它放在我们自己的函数中,命名为“floor”:
- def floor(number):
- result = 0
- while result <= number:
- result = result + 1
- result = result - 1
- return result
复制代码
这个例子中的新东西……
1. 函数用关键字def定义,函数名紧随其后并且要用括号把需要的参数括起来。
2. 如果要求函数返回一个值,要使用关键字return来处理(它同时也自动结束函数定义)。
定义了函数之后,我们可以象这样使用它:
执行后,y的值应该是2。定义拥有多个参数的函数也是可以的:
-
- def sum(x, y):
- return x + y
复制代码
练习3
写一个函数,用欧几里德方法寻找两个数的一个共同因数。工作过程是这样的:
1. 假设两个数,a和b,a大于b
2. 重复以下步骤直到b变成0:
1. a变为b的值
2. b变成没有改变值之前的a除以没有改变值之前的b的余数
3. 返回a的最后一个值
提示:
* 使用a和b作为函数的参数
* 简单的设定a大于b
* x除以z的余数用表达式 x % z 来计算
* 两个变量可以象这样一起赋值:x, y = y, y+1。这里x被赋以值y(这意味着,y的值此前已经指定)而且y被递增了1。
7. 深入函数
上面的练习怎么做?难吗?还不太清楚函数?别担心--我还没完成我的话题呢。
我们构建函数时使用的萃取方法称为过程抽象,许多编程语言把关键字过程同函数一样使用。事实上,这两个概念是不一样的,但是在python中它们都被称为函数(因为它们或多或少以同样的方式定义和使用)。
函数和过程(在其它语言中)的区别在哪里呢?嗯--就像你在前面的段落里看到的那样,函数可以返回一个值。区别就是过程并不返回这样的值。许多时候,用这种方法把函数划分为两种类型--返回值的和不返回值的--是很有用的。
不返回值的函数(过程)可以用作子程序或例行程序。我们调用这些函数,它们制造某些原料,就象泡沫鲜奶之类的。我们可以在很多地方使用这个函数而不需要重写它的代码(这被称为代码再利用--以后你还会知道,它意义不仅仅在这里)。
这样的函数(或过程)的另一个有用性体现在--它改变了环境(例如,把糖和奶油混在一起搅拌,它们的整个外部状态就变化了)让我们看个例子:
- def hello(who):
- print "Hello, ", who
- hello("world")
- # Prints out "Hello, world"
复制代码
打印出内容是它一方面的作用,因为这是这个函数唯一需要做的事,它其实是一个典型的所谓过程。但是……它事实上没有改变它的运行环境,是不是?它怎样才能改变呢?让我们试一下:
- # The *wrong* way of doing it
- age = 0
- def setAge(a):
- age = a
- setAge(100)
- print age
- # Prints "0"
复制代码
错在哪儿?错在函数setAge创建了它自己的也被命名为age的局部变量,它只在setAge函数内部可用。那如何才可以避免出现这个问题呢?我们可以使用全局变量。
注意:全局变量在python中不常用。它们容易引起不好的代码组织结构,被称为意大利面代码。我这里使用它们是为了引出更复杂一点的技术问题--如果你可以请尽量避免使用它们。
未译完。。。 |
|