用Python编程 笔记2

第四章 条件和递归(Conditionals and recursion)

4.1 模除运算符(modulus operator)

模除运算符在Python中是用一个百分比(%)符号来表示的

>>> quotient = 7 / 3
>>> print quotient
2

>>> remainder = 7 % 3
>>> print remainder
1

模除运算符可以用来判断一个数字是否可以被另外一个数字整除—如果 x % y 的结果是0,那么x就能够被y整除

同样还可以用来去除数字中最后位的数字。如:123 % 10返回的结果就是12

4.2 布尔表示法(Boolean expressions)

一个布尔表示法要么是真(true)要么是假(false)

>>> 5 == 5
True
>>> 5 == 6
False

单个等号是赋值号,双等号是比较运算符。还有其他比较运算符:

  • x != y # x不等于y
  • x > y # x大于y
  • x < y # x小于y
  • x >= y # x大于等于y
  • x <= y # x小于等于y

4.3 逻辑运算符(Logical operators)

与(and),或(or),非(not)

4.4 执行条件(Conditional execution)

条件语句(Conditional statement)给我们检查条件和根据条件改变程序的能力

1
2
if x > 0;
  print "x is positive"

可以用pass语句来暂时填充尚未编写的条件语句

4.5 选择执行(Alternative execution)

1
2
3
4
if x%2 == 0:
  print x, "is even"
else:
  print x, "is odd"

这些可能被称为“分支”(brenches),它们都是执行流中的分支

如果要经常用到同样的选择执行,可以将其定义为函数

1
2
3
4
5
def printParity(x):
  if x%2 == 0:
    print x, "is even"
  else:
    print x, "is odd"

4.6 链接条件(Chained conditionals)

1
2
3
4
5
6
if x < y:
  print x, "is less than", y
elif x > y:
  print x, "is greater than", y
else:
  print x, "and", y, "are equal"

elif是else if的缩写

没有else if的数量限制,但是最后一个条件语句一定得是else

4.7 条件嵌套(Nested conditionals)

1
2
3
4
5
6
7
if x == y:
  print x, "and", y, "are equal"
else:
  if x < y:
    print x, "is less than", y
  else:
    print x, "is greater than", y

if语句是一个布尔函数,可以使用复杂的条件判断

1
2
if 0 < x < 10:
  print "x is a positive single digit."

4.8 返回语句(The return statement)

返回语句能够在判断之后就结束一个函数的调用。使用返回语句可以帮助发现错误。

1
2
3
4
5
6
7
8
9
import math
def printLogarithm(x):
  if x <= 0:
    print "Positive numbers only, please."
  return
result = math.log(x)
print "The log of x is", result

4.9 递归(Recursion)

一个函数除了可以在其内调用其他函数以外,还可以调用其本身:

1
2
3
4
5
6
def countdown(n):
  if n == 0:
    print "Blastoff!"
  else:
    print n
    countdown(n-1)

>>> countdown(3)
3
2
1
Blastoff!

1
2
3
4
def nLines(n):
  if n > 0:
    print
    nLines(n-1)

4.10 递归函数的栈图(Stack diagrams for recursive functions)

Stack diagram recurse

4.11 无限递归(Infinite recursion)

一个无限执行下去的递归叫无限递归
Python中无限递归并不能无限进行下去,而是在达到了递归的最大限制数量之后停止运行并且报错:

File “<stdin>”, line 2, in recurse
(98 repetitions omitted)
File “<stdin>”, line 2, in recurse
RuntimeError: Maximum recursion depth exceeded

4.12 键盘输入(Keyboard input)

Python提供自带的取得用户键盘输入的函数,叫 raw_input 当这个函数被调用后,程序会停止运行并且等待用户输入

>>> name = raw_input (“What…is your name? “)
What…is your name? Arthur, King of the Britons!
>>> print name
Arthur, King of the Britons!

括号内的引号内的内容为提示(prompt)

prompt = “What…is the airspeed velocity of an unladen swallow?n”
speed = input(prompt)

>>> speed = input (prompt)
What…is the airspeed velocity of an unladen swallow?
What do you mean, an African or a European swallow?
SyntaxError: invalid syntax

第五章 卓有成效的功能(Fruitful functions)

5.1 返回值(Return values)

如果一个函数能返回值,那么可以将这个值赋予一个变量,或者将函数值作为表达式的一部分:

1
2
e = math.exp(1.0)
height = radius * math.sin(angle)

例1:area 计算圆面积

1
2
3
4
import math
def area(radius):
  temp = math.pi * radius**2
  return temp

temp这个变量只存在于函数中,对函数之外没有意义,可以如下编写来跳过temp

1
2
3
import math
def area(radius):
  return math.pi * radius**2

但是temp这样的临时变量(temporary variables)可以帮助发现bug.

很多时候情况不像area这么简单,可以使用执行条件

例2:absouluteValue 绝对值

1
2
3
4
5
def absoluteValue(x):
  if x < 0:
    return -x
  elif x > 0:
    return x

这个函数存在问题,当输入为0的时候,程序会返回none

>>> print absoluteValue(0)
None

5.2程序开发

为了应对逐渐复杂的程序,建议采用一种技术:增量式开发(递增式发展incremental development)。增量式开发的思想是通过一次次对小段代码的测试来避漫长的调试(debugging)阶段

例3:计算两点之间的距离

第一步,先写出函数的框架

1
2
def distance(x1, y1, x2, y2):
  return 0.0

第二步,在第一步程序中增加横竖坐标差的计算

1
2
3
4
5
6
def distance(x1, y1, x2, y2):
  dx = x2 - x1
  dy = y2 - y1
  print "dx is", dx
  print "dy is", dy
  return 0.0

第三步,计算横竖坐标差的平方的和

1
2
3
4
5
6
def distance(x1, y1, x2, y2):
  dx = x2 - x1
  dy = y2 - y1
  dsquared = dx**2 + dy**2
  print "dsquared is: ", dsquared
  return 0.0

第四步,计算距离

1
2
3
4
5
6
def distance(x1, y1, x2, y2):
  dx = x2 - x1
  dy = y2 - y1
  dsquared = dx**2 + dy**2
  result = math.sqrt(dsquared)
  return result

以上开发过程中,每一步都对该步新增部分进行了测试,以确保程序的正确。

5.3组合(Composition)

例4:给定两个点的坐标,设第一个点为圆心,第二个点为圆上的一点,计算该圆的面积
通过调用前面例子中编写的函数可以轻易完成这个程序的编写
半径计算为:

1
radius = distance(xc, yc, xp, yp)

计算圆面积为:

1
2
result = area(radius)
return result

将两者合起来放到同一个函数中去:

1
2
3
4
def area2(xc, yc, xp, yp):
  radius = distance(xc, yc, xp, yp)
  result = area(radius)
  return result

临时变量radius和result对开发调试有用,但对整个程序没有意义,因此将上面函数改写:

1
2
def area2(xc, yc, xp, yp):
  return area(distance(xc, yc, xp, yp))

5.4布尔函数(Bollean functions)

函数能够返回布尔值,通常用来将复杂的测试置于函数的内部
例5:判断是否能被整除

1
2
3
4
5
def isDivisible(x, y):
  if x % y == 0:
    return True
  else:
    return False

因为if语句本身就是一个布尔表示法,我们可以将上面的程序简化:

1
2
def isDivisible(x, y):
  return x % y == 0

5.5更多递归(More recursion)

frabjuous: An adjective used to describe something that is frabjuous.
例6,阶乘
阶乘的定义如下:

0! = 1
对于任意的n(n不等于0)则
n! = n(n − 1)!

编写阶乘的函数如下:

1
2
3
4
5
6
7
def factorial(n):
  if n == 0:
    return 1
  else:
    recurse = factorial(n-1)
    result = n * recurse
    return result

以输入值3为例

Stack diagram

上面的阶乘函数含有临时变量recurse和result,我们可以简化如下:

1
2
3
4
5
def factorial(n):
  if n == 0:
    return 1
  else:
    return n * factorial(n-1)

5.6飞跃的信任(Leap of faith)

按照执行流的顺序是一种读程序的方式,但是可能会很快便让人卡壳。另外一种方式被称作“飞跃的信任”(leap of faith)。当你看到一个函数调用的时候,相对于立刻就按照执行流的去读那个函数的定义,你可以假设这个函数是正确的,并且能返回一个正确的值。

5.7 另一个例子

例7,利用嵌套来编写斐波纳契函数:

1
2
3
4
5
def fibonacci (n):
  if n == 0 or n == 1:
    return 1
  else:
    return fibonacci(n-1) + fibonacci(n-2)

5.8 类型检查

上例中,如果我们输入一个值1.5结果如何?

>>> factorial (1.5)
RuntimeError: Maximum recursion depth exceeded

这将会是一个无限递归。因为函数过程中无法出现基础情形(base case),也就是n==0的情况。
我们可以利用isinstance函数来检验:

1
2
3
4
5
6
7
8
9
10
11
def factorial (n):
  if not isinstance(n, int):
    print "Factorial is only defined for integers."
    return -1
  elif n < 0:
    print "Factorial is only defined for positive integers."
    return -1
  elif n == 0:
    return 1
  else:
    return n * factorial(n-1)

函数中的前两个条件判断被称为守卫(guardian),用来防止代码采用可能会导致错误的值。

第六章 迭代(Iteration)

6.1多重赋值(Multiple assignment)

变量可以被重复赋值,每一次赋值就将用新的值取代之前的值。

6.2 While语句

例1:利用wihle语句来编写之前的countdown函数

1
2
3
4
5
def countdown(n):
  while n > 0:
    print n
    n = n-1
  print "Blastoff!"

使用while语句后,该函数再不需要使用重复调用,也就不存在递归。
这样的执行流叫做循环(loop)。不断重复而不停止的循环叫无限循环(infinite loop)

6.3表格Tables

例2:利用函数来输出一个log函数的表格

1
2
3
4
x = 1.0
while x < 10.0:
  print x, ’t’, math.log(x)
  x = x + 1.0

‘t’代表一个tab符号,’n代表新的一行’

该程序输出结果为:

1.0      0.0
2.0      0.69314718056
3.0      1.09861228867
4.0      1.38629436112
5.0      1.60943791243
6.0      1.79175946923
7.0      1.94591014906
8.0      2.07944154168
9.0      2.19722457734

例3,利用函数来输出一个2的特定log函数表格

1
2
3
4
x = 1.0
while x < 100.0:
  print x, ’t’, math.log(x)/math.log(2.0)
  x = x * 2.0

输出结果为:

1.0      0.0
2.0      1.0
4.0      2.0
8.0      3.0
16.0    4.0
32.0    5.0
64.0    6.0

6.4 二维表格

例4:打印表格的一行:

1
2
3
4
5
i = 1
while i <= 6:
  print 2*i, ’ ’,
  i = i + 1
print

输出结果为

2      4      6      8      10      12

6.5 封装和扩展(Encapsulation and generalization)

封装Encapsulation是将一段代码包括在一个函数内的过程。
例5:对例4打印表格一行代码的封装,并且将其扩展成以n为基数

1
2
3
4
5
6
def printMultiples(n):
  i = 1
  while i <= 6:
    print n*i, ’t’,
    i = i + 1
  print

如果实参为3则输出结果为

3      6      9      12      15      18

例6,通过重复调用printMultiples函数来打印整个表格

1
2
3
4
i = 1
while i <= 6:
  printMultiples(i)
  i = i + 1

输出结果为:

1      2      3      4      5      6
2      4      6      8      10    12
3      6      9      12    15    18
4      8      12    16    20    24
5      10    15    20    25    30
6      12    18    24    30    36

6.6更多封装(More encapsulation)

例7:将上面最后的代码封装到一个新的函数中:

1
2
3
4
5
def printMultTable():
  i = 1
  while i <= 6:
    printMultiples(i)
    i = i + 1

以上过程是一个常见的开发计划,我们开始在函数外面写一些代码,当我们的代码能满足我们的功能要求的时候,我们再将这些代码封装进函数。

6.7局部变量(Local variables)

上面例子中printMultiples和printMulTables中都含有变量i,但是他们是不同的变量,他们只存在所属的函数内,是局部变量。

6.8更多扩展

如果我们需要打印一个不固定为6个数字一行的表格,我们可以对printMultTable设置一个形式参数:
例8:

1
2
3
4
5
def printMulTable(high):
  i = 1
    while i <= high:
    printMiultiples(i)
    i = i + 1

这样在我们再次调用printMultTable的时候,设置实际参数为7,则输出结果为:

1      2      3      4      5      6
2      4      6      8      10    12
3      6      9      12    15    18
4      8      12    16    20    24
5      10    15    20    25    30
6      12    18    24    30    36
7      14    21    28    35    42

如果我们仍然希望行数和列数一样的话,则需要引入另一个形式参数给printMultiples。
例9

1
2
3
4
5
6
7
8
9
10
11
def printMultiples(n, high):
  i = 1
  while i <= high:
    print n*i, ’t’,
    i = i + 1
  print
def printMultTable(high):
  i = 1
  while i <= high:
    printMultiples(i, high)
    i = i + 1

当我们对程序扩展的时候我们可能会得到一些设想之外的能力。如果我们只要打印一半的表格,避免部分重复。我们可以将例9中的代码

1
printMultiples(i, high)

改成

1
printMultiples(i, i)

这样我们设置实际参数为7,得到的结果为:

1
2      4
3      6      9
4      8      12    16
5      10    15    20    25
6      12    18    24    30    36
7      14    21    28    35    42   49

6.9函数(Functions)

函数的功能:

  1. 将一系列语句封装起来,并赋予名称,便于阅读和调试
  2. 将一个长的程序拆解成不同的部分,将一个个独立的函数单独调试,然后再合成一个完整程序
  3. 使用函数可以促进递归和迭代
  4. 良好设计的函数可以为很多程序所用,可重用

 

How to Think Like a Computer Scientist

How to Think Like a Computer Scientist
Learning with Python

by Allen Downey, Jeff Elkner and Chris Meyers.

PDF Version : Link

Leave a Reply

Your email address will not be published. Required fields are marked *