第二章
球体体积是三分之四倍的圆周率乘以半径立方,求半径为5的球体体积。
假如一本书的封面标价是24.95美元,书店打六折。第一本运费花费3美元,后续每增加一本的运费是75美分。问买60本一共得花多少钱呢?
我早上六点五十二分出门离家,以8:15的节奏跑了一英里,又以7:12的节奏跑了三英 里,然后又是8:15的节奏跑一英里,回到家吃饭是几点?
(一开始看到题目,有点难懂8:15的意思,就去网上看别人做的,在这里就直接粘贴上叭,题目本身意义不大)
第三章
3.14 练习
练习1
写一个名叫right_justify的函数,形式参数是名为s的字符串,将字符串打印,前面流出足够的空格,让字符串最后一个字幕在第70列显示。
right_justify(‘monty’)
monty
提示:使用字符拼接和重复来实现。另外Python还提供了内置的名字叫做len的函数,可以返回一个字符串的长度,比如len(‘monty’)的值就是5了。
def right_justify(s):
print((71-len(s))*(' ')+s);
right_justify('abc')
练习2
你可以把一个函数对象作为一个值赋给一个变量或者作为一个实际参数来传递给其他函数。比如,do_twice就是一个把其他函数对象当做参数的函数,它的功能是调用对象函数两次:
def do_twice(f):
f()
f()
下面是另一个例子,这里用了do_twice来调用一个名叫print_spam的函数两次。
def print_spam():
print('spam’)
do_twice(print_spam)
- 把上面的例子写成脚本然后试一下。
- 修改一下do_twice这个函数,让它接收两个实际参数,一个是函数对象,一个是值,调用对象函数两次,并且赋这个值给对象函数作为实际参数。
- 把print_twice这个函数的定义复制到你的脚本里面,去本章开头找一下这个例子哈。
- 用修改过的这个do_twice来调用print_twice两次,用字符串『spam』传递过去作为实际参数。
- 定义一个新的函数,名字叫做do_four,使用一个函数对象和一个值作为实际参数,调用这个对象函数四次,传递这个值作过去为对象函数的一个形式参数。这个函数体内只要有两个语句就够了,而不是四个。
(1)
def do_twice(f):
f()
f()
def print_spam():
print('spam')
do_twice(print_spam)
(2)
def do_twice(func,arg):
func(arg)
func(arg)
(3)
def print_twice(arg):
print(arg)
print(arg)
(4)
do_twice(print_twice,'spam')
(5)
do_twice(print_twice,'spam')
练习三
注意:这个练习应该只用咱们目前学习过的语句和其他功能来实现。
1.写一个函数,输出如下:
提示:要一次打印超过一行,可以用逗号分隔一下就能换行了。如下所示:
默认情况下,print会打印到下一行,你可以手动覆盖掉这个行为,在末尾输出一个空格就可以了:
def latticeA():
print ("+-------+-------+-------+-------+")
print ("| | | | |")
print ("| | | | |")
print ("| | | | |")
def latticeB():
print ("+-------+-------+-------+-------+")
for i in range (4):
latticeA()
latticeB()
第四章
4.3 练习
1.写一个函数叫做square(译者注:就是正方形的意思),有一个名叫t的参数,这个t是一个turtle。用这个turtle来画一个正方形。写一个函数调用,把bob作为参数传递给square,然后再运行这个程序。
import turtle
bob=turtle.Turtle()
def square(t,length):
for i in range(4):
t.fd(length)
t.lt(90)
square(bob,165)
2.给这个square函数再加一个参数,叫做length(译者注:长度)。把函数体修改一下,让长度length赋值给各个边的长度,然后修改一下调用函数的代码,再提供一个这个对应长度的参数。再次运行一下,用一系列不同的长度值来测试一下你的程序。
import turtle
bob=turtle.Turtle()
def square(t,length):
for i in range(4):
t.fd(length)
t.lt(90)
square(bob,165)#165随便改成其他数字
3.复制一下square这个函数,把名字改成polygon(译者注:意思为多边形)。另外添加一个参数叫做n,然后修改函数体,让函数实现画一个正n边的多边形。提示:正n多边形的外角为360/n度。
4.在写一个叫做circle(译者注:圆)的函数,也用一个turtle类的对象t,以及一个半径r,作为参数,画一个近似的圆,通过调用polygon函数来近似实现,用适当的边长和边数。用不同的半径值来测试一下你的函数。
提示:算出圆的周长,确保边长乘以边数的值(近似)等于圆周长。
import math
import turtle
bob=turtle.Turtle()
def polygon(t,length,step_angle,n):
for i in range(n):
t.fd(length)
t.lt(step_angle)
def circle(r,angle):
circumference=2*math.pi*r*angle/360
n=int(circumference/3)+1
length=circumference/n
step_angle=angle/n
polygon(bob,length,step_angle,n)
circle(100,360)
5.在circle基础上做一个叫做arc的函数,在circle的基础上添加一个angle(角度)变量,用这个角度值来确定画多大的一个圆弧。用度做单位,当angle等于360度的时候,arc函数就应当画出一个整团了。
#引入数学模块、乌龟模块
import math
import turtle
#调用乌龟画图、提高画弧速度
bob = turtle.Turtle()
bob.delya = 0.01
#多边线
def polyline(t, n, length, angle):
for i in range(n):
t.fd(length)
t.lt(angle)
#弧
def arc(t, angle, arc_length):
#计算:弧分几段画,每段多长,每段之间的夹角
n = int(arc_length / 4) + 3
step_length = arc_length / n
step_angle = float(angle) / n
#画出弧
t.lt(step_angle/2)
polyline(t, n, step_length, step_angle)
t.rt(step_angle/2)
#不重叠花瓣的花朵
def flower(l,m):
#计算:弧度、弧半径、弧长
arc_angle = 2 * math.pi / m
arc_angle2 = 360 / m
arc_r = l / 2 / math.sin(arc_angle/2)
arc_length = arc_angle * arc_r
#计算:花瓣尖转角度数
angel = 180 - 360.0/m
#画出花朵
for i in range(m):
arc(bob, arc_angle2, arc_length)
bob.lt(angel)
arc(bob, arc_angle2, arc_length)
bob.lt(180)
#重叠花瓣的花朵
def flower2(l,n):
m = int(n/2)
flower(l,m)
bob.lt(180/m)
flower(l,m)
bob.rt(180/m)
#左移240,画出不重叠花瓣的7瓣花
bob.pu()
bob.fd(-240)
bob.pd()
flower(100,7)
#右移240,画出重叠花瓣的10瓣花
bob.pu()
bob.fd(240)
bob.pd()
flower2(100,10)
#左移240,画出不重叠花瓣的20瓣花
bob.pu()
bob.fd(240)
bob.pd()
flower(100,20)
#下移120,让turtle不遮挡花朵
bob.pu()
bob.rt(90)
bob.fd(120)
turtle.mainloop()
第五章
练习1
time模块提供了一个名字同样叫做time的函数,会返回当前格林威治时间的时间戳,就是以某一个时间点作为初始参考值。在Unix系统中,时间戳的参考值是1970年1月1号。
(译者注:时间戳就是系统当前时间相对于1970.1.1 00:00:00以秒计算的偏移量,时间戳是惟一的。)
import time
time.time() 1437746094.5735958
写一个脚本,读取当前的时间,把这个时间转换以天为单位,剩余部分转换成小时-分钟-秒的形式,加上参考时间以来的天数。
import time
t1=time.time()
minute=60
hour=60*minute
day=24*hour
day1=t1//day
hour1=t1%day//hour
min=t1%day%hour//minute
sec=t1%minute
print("当前时间距离1970年1月1日已过去:",day1,"天",hour1,"小时",min,"分钟",sec,"秒。")
练习2
费马大定理内容为,a、b、c、n均为正整数,在n大于2的情况,下面的等式关系不成立:
- 写一个函数,名叫check_fermat,这个函数有四个形式参数:a、b、c以及n,检查一下费马大定理是否成立,看看在n大于2的情况下下列等式是否成立。
- 要求程序输出『Holy smokes, Fermat was wrong!』或者『No, that doesn’t work.』
- 写一个函数来提醒用户要输入a、b、c和n的值,然后把输入值转换为整形变量,接着用check_fermat这个函数来检查他们是否违背了费马大定理。
(1)、(2)
def check_fermat(a,b,c,n):
if(a**n+b**n==c**n):
print('Holy smokes,Fermat was wrong!')
else:
print('No,that does\'t work.')
check_fermat(6,6,6,6)
(3)
def check_fermat(a,b,c,n):
if n>2 and a**n+b**n==c**n:
print('Holy smokes,Fermat was wrong!')
else:
print('No,that does\'t work.')
prompt='Please enter the value of a.\n'
a=int(input(prompt))
prompt='Please enter the value of b.\n'
b=int(input(prompt))
prompt='Please enter the value of c.\n'
c=int(input(prompt))
prompt='Please enter the value of n.\n'
n=int(input(prompt))
check_fermat(a,b,c,n)
给你三根木棍,你能不能把它们拼成三角形呢?有一个简单的方法来检测它们能否拼成三角形:
只要三个木棍中有任意一个的长度大于其他两个的和,就拼不成三角形了。必须要任意一个长度都小于两边和才能拼成三角形。
- 写一个叫做is_triangle的函数,用三个整形变量为实际参数,函数根据你输入的值能否拼成三角形来判断输出『Yes』或者『No』。
- 写一个函数来提示下用户,要输入三遍长度,把它们转换成整形,用is_triangle函数来检测这些给定长度的边能否组成三角形。
(1)
def is_triangle(a,b,c):
if(a>0 and b>0 and c>0):
if((a+b>c)and(a+c>b)and(b+c>a)):
print("Yes!")
else:
print("No!")
is_triangle(1,2,3)
(2)
def is_triangle(a,b,c):
if ((a+b>c) and (a+c>b)and (b+c>a)):
print("Yes")
else:
print("No")
prompt='Please enter the value of a.\n'
a=int(input(prompt))
prompt='Please enter the value of b.\n'
b=int(input(prompt))
prompt='Please enter the value of c.\n'
c=int(input(prompt))
is_triangle(int(a),int(b),int(c))
练习4
下面的代码输出会是什么?画一个栈图来表示一下如下例子中程序输出结果时候的状态。
- recurse(-1, 0)这样的调用函数会有什么效果?
def recurse(n, s):
if n == 0:
print(s)
else:
recurse(n-1, n+s)
recurse(3, 0)
- 为这个函数写一个文档字符串,解释一下用法(仅此而已)。
练习5
阅读下面的函数,看看你能否弄清楚函数的作用。运行一下试试(参考第四章里面的例子来酌情修改代码)。
def draw(t, length, n):
if n == 0:
return
angle = 50
t.fd(length*n)
t.lt(angle)
draw(t, length, n-1)
t.rt(2*angle)
draw(t, length, n-1)
t.lt(angle)
t.bk(length*n)
练习6
Koch科赫曲线是一种分形曲线,外观如图5.2所示。要画长度为x的这种曲线,你要做的步骤如下:
- 画一个长度为三分之一x的Koch曲线。
- 左转60度。
- 画一个长度为三分之一x的Koch曲线。
- 右转120度。
- 画一个长度为三分之一x的Koch曲线。
- 左转60度。
- 画一个长度为三分之一x的Koch曲线。
特例是当x小于3的时候:这种情况下,你就可以只画一个长度为x的直线段。
第六章
- 下面的程序输出会是什么样的?
def b(z):
prod = a(z, z)
print(z, prod)
return prod
def a(x, y):
x = x + 1
return x * y
def c(x, y, z):
total = x + y + z
square = b(total)**2
return square
x = 1
y = x + 1
print(c(x, y+3, x+y))
结果:
9 90
8100
- Ackermann阿克曼函数的定义如下:
写一个叫做ack的函数,实现上面这个阿克曼函数。用你写出的函数来计算
ack(3, 4),结果应该是125.看看m和n更大一些会怎么样。
def ack(m,n):
if m==0:
# print(n+1)
return n+1
elif m>0 and n==0:
return ack(m-1,1)
elif m>0 and n>0:
return ack(m-1,ack(m,n-1))
else:
print('ERROR')
print(ack(3,4))
大了就会报错
- 回文的词特点是正序和倒序拼写相同,比如noon以及redivider。用递归的思路来看,回文词的收尾相同,中间部分是回文词。
下面的函数是把字符串作为实际参数,然后返回函数的头部、尾部以及中间字母:
def first(word):
return word[0]
def last(word):
return word[-1]
def middle(word):
return word[1:-1]
写一个名叫is_palindrome的函数,使用字符串作为实际参数,根据字符串是否为回文词来返回真假。注意,你可以用内置的len函数来检查字符串的长度。
def first(word):
return word[0]
def last(word):
return word[-1]
def middle(word):
return word[1:-1]
def is_p(s):
if len(s)==0 or len(s)==1:
return True
if first(s)==last(s):
return is_p(middle(s))
else:
return False
print(is_p('noon'))
True
-
一个数字a为b的权(power),如果a能够被b整除,并且a/b是b的权。写一个叫做is_power的函数接收a和b作为形式参数,如果a是b的权就返回真。注意:要考虑好基准条件。
题目有问题 -
a和b的最大公约数是指能同时将这两个数整除而没有余数的数当中的最大值。找最大公约数的一种方法是观察,如果当r是a除以b的余数,那么a和b的最大公约数与b和r的最大公约数相等。基准条件是a和0的最大公约数为a。
写一个有名叫gcd的函数,用a和b两个形式参数,返回他们的最大公约数。
def gcd(a,b):
if b==0:
return a
return gcd(b,a%b)
print(gcd(3,6))
3
在函数的开头结尾添加输出语句,能够确保整个执行流程更加可视化。比如下面就是一个有输出版本的阶乘函数:
def factorial(n):
space = ' ' * (4 * n)
print(space, 'factorial', n)
if n == 0:
print(space, 'returning 1’)
return 1
else:
recurse = factorial(n-1)
result = n * recurse
print(space, 'returning', result)
return result
space在这里是一串空格的字符串,是用来缩进输出的。下面就是4的阶乘得到的结果:
factorial 4
factorial 3
factorial 2
factorial 1
factorial 0
returning 1
returning 1
returning 2
returning 6
returning 24
def factorial(n):
space = ' ' * (4 * n)
print(space, 'factorial', n)
if n == 0:
print(space, 'returning 1')
return 1
else:
recurse = factorial(n-1)
result = n * recurse
print(space, 'returning', result)
return result
print(factorial(6))
factorial 6
factorial 5
factorial 4
factorial 3
factorial 2
factorial 1
factorial 0
returning 1
returning 1
returning 2
returning 6
returning 24
returning 120
returning 720
720
第七章
- 从7.5小节复制一个循环,然后改写成名字叫做mysqrt的函数,该函数用一个a作为参数,选择一个适当的起始值x,然后返回a的平方根的近似值。
测试这个函数,写一个叫做test_suqare_root的函数做如下输出:
第一列是数a;第二列是咱们自己写的函数mysqrt计算出来的平方根,第三行是用Python内置的math.sqrt函数计算的平方根,最后一行是这两者的差值的绝对值。
import math
def square_root(a):
x = a
y = 0
while True:
y = (x+a/x)/2.0
if abs(y-x) < 1e-2:
break
x = y
return y
def test_square_root():
print('a\tmysqrt(a)\tmath.sqrt(a)\tdiff')
print('-\t---------\t------------\t----')
for a in range(1,10):
mysqrt=square_root(a)
mathsqrt=math.sqrt(a)
print('%.1lf\t%lf\t%lf\t%lf' % (a,mysqrt, mathsqrt, abs(mysqrt-mathsqrt)))
test_square_root()
- Python的内置函数eval接收字符串作为参数,然后用Python的解释器来运行。例如:
写一个叫做eval_loop的函数,交互地提醒用户,获取输入,然后用eval对输入进行运算,把结果打印出来。
eval(‘1 + 2 * 3’)
7import math
eval(‘math.sqrt(5)’)
2.2360679774997898eval(‘type(math.pi)’)
<class ‘float’>
这个程序要一直运行,直到用户输入『done』才停止,然后输出最后一次计算的表达式的值。
import math
def eval_loop():
ans=’’
while True:
s=input(‘请输入:\n’)
if s==‘done’:
return ans
#break
ans=eval(s)
print(ans)
print(eval_loop())
3.传奇的数学家拉马努金发现了一个无穷级数(1914年的论文),能够用来计算圆周率倒数的近似值:
写一个名叫estimate_pi的函数,用上面这个方程来计算并返回一个圆周率π的近似值。要使用一个while循环来计算出总和的每一位,最后一位要小于10的-15次方。你可以对比一下计算结果和Python内置的math.pi。
import math
def factorial(n):
if n == 0:
return 1
else:
return n*factorial(n-1)
def estimate_pi():
total=0
k=0
factor=2*math.sqrt(2)/(99**2)
while True:
num= factorial(4*k) * (26390*k +1103)
den= factorial(k)**4 * 396**(4*k)
term = factor * num / den
total += term
if abs(term)<1e-15:
break
k=k+1
return 1 / total
print(estimate_pi())
print(math.pi)
第八章
下面的例子展示了如何使用级联(字符串加法)以及一个 for 循环来生成一个简单的序列(用字母表顺序)。
prefixes = 'JKLMNOPQ'
suffix = 'ack'
for letter in prefixes:
print(letter + suffix)
在 Robert McCloskey 的一本名叫《Make Way for Ducklings》的书中,小鸭子的名字依次为:Jack, Kack, Lack, Mack, Nack, Ouack, Pack, 和Quack。下面这个循环会依次输出他们的名字:
输出结果如下:Jack Kack Lack Mack Nack Oack Pack Qack
当然了,有点不准确的地方,因为有“Ouack”和 “Quack”两处拼写错了。做个练习,修改一下程序,改正这个错误。
prefixes = 'JKLMNOPQ'
suffix = 'ack'
for letter in prefixes:
if letter=='O' or letter=='Q':
print(letter+'u'+suffix)
else:
print(letter + suffix)
简单来说,find 函数,也就是查找,可以理解成是方括号操作符[]的逆运算。方括号是之道索引然后提取对应的字符,而查找函数是选定一个字符去查找这个字符出现的索引位置。如果字符没有被报道,函数就返回-1
做个练习,修改一下 find 函数,加入第三个参数,这个参数为查找开始的字符串位置。
做个练习,把上面的代码封装进一个名叫 count 的函数中,泛化一下,一遍让他接收任何字符串和字母作为参数。然后再重写一下这个函数,这次不再让它遍历整个字符串,而使用上一节中练习的三个参数版本的 find 函数。
def find(word, letter):
index = 0
while index < len(word):
if word[index] == letter:
return index
index = index + 1
return -1
print(find('abab','a'))
1.凯撒密码是一种简单的加密方法,用的方法是把每个字母进行特定数量的移位。对一个字母移位就是把它根据字母表的顺序来增减对应,如果到末尾位数不够就从开头算剩余的位数,『A』移位3就是『D』,而『Z』移位1就是『A』了。
要对一个词进行移位,要把每个字母都移动同样的数量。比如『cheer』这个单词移位7就是『jolly』,而『melon』移位-10就是『cubed』。在电影《2001 太空漫游》中,飞船的电脑叫 HAL,就是 IBM 移位-1。
写一个名叫 rotate_word 的函数,接收一个字符串和一个整形为参数,返回将源字符串移位该整数位得到的新字符串。
你也许会用得上内置函数 ord,它把字符转换成数值代码,然后还有个 chr 是用来把数值代码转换成字符。字母表中的字母都被编译成跟字母表中同样的顺序了,所以如下所示:
ord(‘c’) - ord(‘a’)
2
def rotate_letter(letter, n):
#数字部分进行位移
if 48<=ord(letter)<=57:
start2 = ord('0')
d=ord(letter)-start2
q=(d+n)%10+start2
return chr(q)
#字母部分进行位移
else:
if letter.isupper():
start = ord('A')
elif letter.islower():
start = ord('a')
else:
return letter
c = ord(letter) - start
i = (c + n) % 26 + start
return chr(i)
def rotate_word(word,n):
res=''
for letter in word:
res+=rotate_letter(letter,n)
# res+=(rotate_letter(letter,n)+is_number(letter,n))
return res
print(rotate_word('z', 7))
print(rotate_word('Mel0on', -10))
print(rotate_word('sle7ep', 9))
print(rotate_word('666',8))
第九章
1.写一个程序读取 words.txt,然后只输出超过20个字母长度的词(这个长度不包括转义字符)。
fin =open('C:/Users/laptop/Desktop/words.txt')
for line in fin:
word=line.strip()
if len(word)>20:
print(word+'\n')
2.写一个名字叫做 has_no_e 的函数,如果给定词汇不含有 e 就返回真,否则为假。修改一下上一节的程序代码,让它只打印单词表中没有 e 的词汇,并且统计一下这些词汇在总数中的百分比例。
def has_no_e(word):
if not('e' in word):
# print('True')
return True
else:
#print('False')
return False
fin=open('C:/Users/laptop/Desktop/words.txt')
i=0
j=0
for line in fin:
word=line.strip()
if has_no_e(word):
#print(word)
i=i+1
j=j+1
print(i/j*100,'%')
3.写一个名叫 avoids 的函数,接收一个单词和一个禁用字母组合的字符串,如果单词不含有该字符串中的任何字母,就返回真。 修改一下程序代码,提示用户输入一个禁用字母组合的字符串,然后输入不含有这些字母的单词数目。你能找到5个被禁用字母组合,排除单词数最少吗?
def avoids(word, str):
for letter in word:
for line in str:
if letter == line:
return False
return True
fin = open('C:/Users/laptop/Desktop/words.txt')
str = input('Please enter a string:')
x = 0
for line in fin:
word = line.strip()
if avoids(word, str):
x = x+1
print(x)
- 写一个名叫uses_only的函数,接收一个单词和一个字母字符串,如果单词仅包含该字符串中的字母,就返回真。
import re
from functools import wraps
def get_alpha_str4(s):
result = ''.join(re.split(r'[^A-Za-z]', s))
return result
def uses_only(word,s):
w=get_alpha_str4(word.lower())
for letter in w:
if not(letter in s):
return False
return True
if uses_only('Hoe alfalfa7q','acefhlo'):
print('True')
else:
print('False')
- 写一个名字叫uses_all的函数,接收一个单词和一个必需字母组合的字符串,如果单词对必需字母组合中的字母至少都用了一次就返回真。有多少单词都用到了所有的元音字母 aeiou?或aeiouy的呢?
def uses_all(word, str):
for letter in str:
if letter not in word:
return False
return True
fin = open('C:/Users/laptop/Desktop/words.txt')
n = 0
for line in fin:
word = line.strip()
if uses_all(word, 'aeiouy'):
n = n+1
print(word)
print(n)
- 写一个名字叫is_abecedarian的函数,如果单词中所有字母都是按照字母表顺序出现就返回真(重叠字母也是允许的)。有多少这样的单词?
def is_abecedarian(word):
i = 1
for letter in word:
for j in range(i, len(word)):
if letter >= word[j]:
if j == i and letter == word[j]:
continue
return False
i = i+1
return True
fin = open('C:/Users/laptop/Desktop/words.txt')
n = 0
for line in fin:
word = line.strip()
if is_abecedarian(word):
n = n+1
print(n, word)