递归函数
递归函数是调用自身的函数。为了防止函数无限次地重复调用自己,它必须至少包含一条选择语句。这条语句检查一个叫作基本条件(base case)的条件,来判断是停止还是继续递归的步骤。
我们来看看如何把一个迭代算法转换为一个递归函数。如下是一个名为 displayRange的递归函数的定义,它输出从下边界到上边界的数字:
def displayRange(lower, upper): """Outputs the numbers from lower to upper.""" while lower <= upper: print(lower) lower = lower + 1
如何将这个函数转换为递归函数呢?首先,需要注意两点重要的情况:
- 当 lower<=upper 的时候,循环体继续执行;
- 当函数执行的时候,lower 增加 1,但是 upper 不变。
等价的递归函数可以执行类似的基本操作,但是,用一条 if 语句替代了循环,用函数的递归调用替代了赋值语句。如下是做出这些修改后的代码:
def displayRange(lower, upper): """Outputs the numbers from lower to upper.""" if lower <= upper: print(lower) displayRange(lower + 1, upper)
尽管两个函数的语法和设计是不同的,但它们所执行的算法过程是相同的。递归函数的每次调用,都会按照顺序访问下一个数,这和函数的迭代版本中的循环所做的事情是一样的。
大多数递归函数都至少接受一个参数。这个数据值测试结束递归过程的基本条件。在每一个递归步骤之前,也会以某种方式修改这个值。每次对数据值的修改,都应该会产生一个新的数据值,以允许函数最终达到基本条件。在 displayRange 的例子中,也就是在每一次递归调用之前,将参数 lower 的值增加 1,以使得其最终能够超过参数 upper 的值。
下面是递归函数的另一个示例,它生成并返回一个值。Python 的 sum 函数接受数字的一个集合,并且返回它们的加和。这个函数应该会返回从下界到上界的数字的加和。如果lower 超过了 upper(基本条件),递归函数 ourSum 会返回 0。否则的话,该函数会把lower 和针对 lower+1 与 upper 执行 ourSum 的结果相加,并且返回最终的结果:
def ourSum(lower, upper): """Returns the sum of the numbers from lower thru upper.""" if lower > upper: return 0 else: return lower + ourSum(lower + 1, upper)
对 ourSum 的递归调用,会将数字从 lower+1 一直加到 upper。然后,这个函数把lower 和结果相加,并将其返回。
类和对象
类描述了数据以及和一组对象相关的方法。类提供了一个蓝图,可以用来创建对象以及在这些对象上调用方法的时候所执行的代码。Python 中所有的数据类型都是类。
定义 Python 类的语法如下:
def <class name>(<parent class name>): <class variable assignments> <instance method definitions>
按照惯例,类名是要大写的。类定义的代码通常放在模块中,该模块的文件名和类名一样,但是是小写的。相关的类也可以出现在同一模块中。父类名是可选的,在这种情况下,会假设它是 object。所有的 Python 类都位于层级之中,object 在这个层级的根部。有几个方法如str和eq均定义于 object 中并且是所有的子类会自动继承的。实例方法在类的对象之上运行,它们包含了访问或修改实例变量的代码。实例变量引用了单个对象所拥有的存储。类变量引用了类的所有对象共同拥有的存储。
为了说明这些思路,本节现在将定义一个 Counter 类的代码。正如其名,Counter 对象用来记录整数。计数器的值最初为 0,并且可以随时将其重新设置为 0。我们可以递增或递减一个计数器,获取其当前的整数值,获取其字符串表示,或者比较两个计数器是否相等。
该类的代码如下:
""" File: counter.py Defines a Counter class for counting. """ class Counter(object): """Models a counter.""" # Class variable instances = 0 #Constructor def __init__(self): """Sets up the counter.""" Counter.instances += 1 self.reset() # Mutator methods def reset(self): """Sets the counter to 0.""" self._value = 0 def increment(self, amount = 1): """Adds amount to the counter.""" self._value += amount def decrement(self, amount = 1): """Subtracts amount from the counter.""" self._value -= amount # Accessor methods def getValue(self): """Returns the counter's value.""" return self._value def __str__(self): """Returns the string representation of the counter.""" return str(self._value) def __eq__(self, other): """Returns True if self equals other or False otherwise.""" if self is other: return True if type(self) != type(other): return False return self._value == other._value
如下是在 Python shell 中和一些 Counter 对象的交互代码:
>>>from counter import Counter >>>c1=Counter() >>>print(c1) 0 >>>c1.getValue()0 >>>str(c1) ’0’ >>>c1.increment() >>>print(c1) 1 >>>c1.increment(5) >>>print(c1) 6 >>>c1.reset() >>>print(c1) 0 >>>c2=Counter() >>>Counter.instances 2 >>>c1==c1 True >>>c1==0 False >>>c1==c2 True >>>c2.increment() >>>c1==c2 False >>>
现在我们来简单介绍一下,Counter 类是 object 的一个子类。
类变量 instances 记录了所创建的 Counter 对象的数目。除了最初在通过赋值引入类变量的时候之外,在其他时候,类变量必须有一个类名作为其前缀。定义实例方法的语法,和定义函数的语法是相同的。然而,有一个叫作 self 的、额外的参数,它总是出现在参数列表的开始处。在一个方法定义的上下文中,self 引用的是在其上运行该方法的那个对象。
实例方法init也叫作构造方法,当创建 Counter 的实例的时候,会自动运行其构造方法。该方法初始化了实例变量并且更新了类变量。注意,init使用了 self.reset()的语法,调用了实例方法 reset,以初始化单个的实例变量。其他的实例方法分为两类:修改器(mutator)方法和访问器(accessor)方法。修改器方法通过修改对象的实例变量,来修改或改变对象的内部状态。访问器方法直接查看或使用对象的实例变量的值,而不会修改它们。
在初次调用实例方法 reset 的时候,它引入了实例变量 self.value。随后,对该方法的任何其他的调用,都会将这个实例变量的值修改为 0。一个实例变量总是有一个 self前缀。与参数或临时变量不同,实例变量在类的任何方法之中都是可见的。一些类的实例变量拼写为带有一个字符前缀。这个惯例有助于读者将其与参数以及临时变量
区分开来,并且这也不鼓励代码编写者在类定义之外访问实例变量。
increment 和 decrement 方法使用默认的参数,这允许程序员来选择指定还是不指定这个量。Counter 类中的str方法覆盖了 object 类中的相同的方法。当把对象作为参数传递给 str 函数的时候,python 在该对象上运行str。当在一个对象上运行一个方法的时候,Python 首先在该对象自己的类中查找该方法的代码。如果没有在那里找到这个方法,Python 会在其父类中查找,依次类推。如果最终没有找到该方法的代码(在 object类中查找完了之后),Python 会抛出一个异常。
当 Python 的 print 函数接受参数的时候,会自动运行该参数的str方法,获取其字符串表示以用于输出。我们鼓励程序员为每一个自定义的类都包含一个str方法,以帮助进行调试。
当 Python 看到==的时候,它会运行eq方法。该方法默认地定义在 object 类中,它运行 is 运算符,该运算符会比较两个运算数的对象相等性。正如你所看到的,只要两个不同的 counter 对象拥有相同的值,我们就让视作它们是相等的。因为==的第二个运算数
可以是任何的对象,eq方法在访问它们的实例变量之前,会询问运算数的类型是否是相同的。注意,我们在对象上使用了点表示法来访问实例变量。
文件操作
文本文件的输出
根据文本文件的格式和数据的用途,我们可以将文本文件中的数据看做是字符、单词、数字或者文本行。当把这些数据当作整数或浮点数的时候,必须用空白字符(空格、制表符和换行符)将其分隔开。例如,当使用一个文本编辑器查看包含 6 个浮点数的一个文本文件的时候,如下所示:
34.6 22.33 66.75 77.12 21.44 99.01
注意,该格式用空格或换行作为文本中的各项的分隔符。文本文件的所有数据输出或数据输入都必须是字符串。因此,在输出之前,这些数字必须先转换为字符串,并且在输入之后,这些字符串必须再转换为数字。可以使用文件对象将数据输出到文本文件中。Python 的 open 函数接受文件的路径名称和模式字符串作为参数,它打开到磁盘上的文件的一个连接,并且返回文件对象。模式字符串’r’表示输入文件,’w’表示输出文件。因此,如下的代码在名为 myfile.txt的文
件上打开一个文件对象以进行输出:
>>>f=open("myfile.txt",’w’)
如果该文件并不存在,会使用给定的路径名称来创建它。如果该文件已经存在,Python 会打开它。当数据写入到文件并且文件关闭的时候,文件中之前存在的任何数据都将会被擦除。我们使用 write 方法和文件对象,将字符串数据写入(或输出)到一个文件之中。write
方接受单个的字符串参数。如果你想要输出文本并且以换行来结束,必须在字符串中包含转义字符\n。下面的语句将两行文本写入到了文件中:
>>> f.write("First line.\nSecond line.\n")
当所有的输出完成之后,应该使用 close 方法来关闭文件,如下所示:
>>> f.close()
如果没有能够成功地关闭输出的文件,将会导致数据丢失。
将数字写入到一个文本文件
文件方法 write 接受字符串作为参数。因此,其他类型的数据,例如整数或浮点数,必须先转换成字符串,然后才能写入到输出文件中。在 Python 中,大多数数据类型的值都可以使用 str 函数来转换为字符串。然后,使用空格或换行作为分隔符字符,将所得到的字符串写入到文件中。
下面的代码段展示了如何将整数输出到文本文件中。生成 1 到 500 之间的 500 个随机的整数,并将其写入到名为 integers.txt 的文本文件中。换行字符作为分隔符。
import random f=open("integers.txt",'w') for count in range(500): number = random.randint(1, 500) f.write(str(number) + "\n") f.close()
从文本文件读取文本
打开一个文件进行输入的方式,和打开一个文件进行输出的方式相同。唯一的变化在于模式字符串。在打开文件进行输入的情况下,使用’r’字符串。然而,如果路径名是从当前的工作目录无法访问的,Python 会产生错误。打开 myfile.txt 文件进行输入的代码如下:
>>>f=open("myfile.txt",’r’)
有几种方法可以实现从输入文件读取数据。最简单的方法是使用文件方法 read 来将整个文件的内容作为一个单独的字符串输入。如果文件包含了多行文本的话,换行字符将会嵌入到这个字符串中。下面的这个 shell 会话展示了如何使用 read 方法:
>>> text=f.read() >>> text ’First line. \nSecond line. \n’ >>>print(text) First line. Second line. >>>
在输入完成后,再次调用 read 将会返回一个空的字符串,表明已经到达了文件的末尾。要重复输入,必须再次打开文件。这样的话,就不必关闭该文件了。此外,一个应用程序可能每次只读取和处理一行文本。一个 for 循环就可以很好地完成这一任务。这个 for 循环将一个文件对象当作是文本行的一个序列。在每次通过循环的时候,循环变量都跳到序列中的下一行文本。如下的会话重新打开示例文件并访问其中的每一行文本:
>>>f=open("myfile.txt",’r’) >>>for line in f: print(line) First line. Second line. >>>
注意,print 似乎输出了一个额外的换行。这是因为从文件输入的每一行文本,都包含一个换行字符。当你想要从一个文件读取特定数目的行的时候(例如,只读取第 1 行),可以使用文件方法 readline。readline 方法只读取一行的输入并且返回该字符串,包括换行符。如果 readline 遇到了文件的末尾,它会返回空字符串。下面的代码段使用一个 while True循环并用 readline 输入所有的文本行:
>>>f=open("myfile.txt",’r’) >>> while True: line = f.readline() if line == "": break print(line) First line. Second line. >>>
python编程练习题
1.有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13…求出这个数列的前20项之和。
from functools import reduce def cal_sum(): fenzi = 2 fenmu = 1 lst = [2] for i in range(1,20): fenmu,fenzi= fenzi,fenmu+fenzi lst.append(fenzi / fenmu) return reduce(lambda x,y:x+y,lst) print(cal_sum())
2.给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
def num_reverse(num): print(' '.join(str(num))) numLen = len(str(num)) print(numLen) for i in range(numLen): toPrint = num % 10 num = int((num - toPrint)/10) print(toPrint,end=' ') num_reverse(9523684)
- 有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
def who_remain(n): lst = list(range(1, n+1)) while n > 2: lst.pop(2) before = lst[:2] lst = lst[2:] lst.extend(before) n = len(lst) return lst[-1] print(who_remain(29))
4.题:编写一个程序,根据控制台输入的事务日志计算银行帐户的净金额。 事务日志格式如下所示:
D 100
W 200
D表示存款,而W表示提款。
假设为程序提供了以下输入:
D 300
D 300
W 200
D 100
然后,输出应该是:
500
netAmount = 0 while True: print("请输入:") s = input() if not s: break values = s.split(" ") operation = values[0] amount = int(values[1]) if operation=="D": netAmount+=amount elif operation=="W": netAmount-=amount else: pass print (netAmount)
5.机器人从原点(0,0)开始在平面中移动。 机器人可以通过给定的步骤向上,向下,向左和向右移动。 机器人运动的痕迹如下所示:
UP 5
DOWN 3
LETF 3
RIGHT 2
方向之后的数字是步骤。 请编写一个程序来计算一系列运动和原点之后距当前位置的距离。如果距离是浮点数,则只打印最接近的整数。
例:如果给出以下元组作为程序的输入:
UP 5
DOWN 3
LETF 3
RIGHT 2
然后,程序的输出应该是:2
import math pos = [0, 0] print("请输入:") while True: s = input() if not s: break movement = s.split(" ") direction = movement[0] steps = int(movement[1]) if direction == "UP": pos[0] += steps elif direction == "DOWN": pos[0] -= steps elif direction == "LEFT": pos[1] -= steps elif direction == "RIGHT": pos[1] += steps else: pass print(int(round(math.sqrt(pos[1] ** 2 + pos[0] ** 2))))
python字符串练习题
1.判断用户输入的变量名是否合法:
1.变量名可以由字母,数字或者下划线组成
2.变量名只能以字母或者下划线开头
分析:
1.判断变量名的第一个元素是否为字母或者下划线 s[0]
2.如果第一个元素符合条件,判断除了第一个元素之外的其他元素s[1:]
while True: s = input('变量名:') if s == 'q': exit() # 判断首字母是否符合变量名要求 if s[0] == '_' or s[0].isalpha(): # 依次判断剩余的所有字符 for i in s[1:]: # 只要有一个字符不符合,便不是合法的变量;alnum表示字母或数字 if not (i.isalnum() or i == '_'): print('%s不是一个合法的变量名' % s) break else: print('%s是一个合法的变量名' % s) else: print('%s不是一个合法的变量名' % s)
2.给定一个字符串来代表一个学生的出勤纪录,这个纪录仅包含以下三个
字符:
'A' : Absent,缺勤
'L' : Late,迟到
'P' : Present,到场
如果一个学生的出勤纪录中不超过一个'A'(缺勤)并且不超过两个连续的'L'(迟到),
那么这个学生会被奖赏。
你需要根据这个学生的出勤纪录判断他是否会被奖赏。
示例 1:
输入: "PPALLP"
输出: True
示例 2:
输入: "PPALLL"
输出: False
print(""" 出勤记录规则 'A' : Absent 缺勤 'L' : Late 迟到 'P' : Present 到场 """) while True: c = input('请输入考勤记录:') # count() 表示指定字符出现的次数 if c.count('A') <= 1 and c.count('LLL') == 0 and c != 'q': print('True') elif c == 'q': exit() else: print('False')
3.输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例
如,输入”They are students.”和”aeiou”,
则删除之后的第一个字符串变成”Thy r stdnts.”
- 输入描述:
每个测试输入包含2个字符串 - 输出描述:
输出删除后的字符串 - 示例1:
输入
They are students.
aeiou
输出
Thy r stdnts.
s1 = input('s1:') s2 = input('s2:') # 遍历字符串s1 for i in s1: # 依次判断s1中的每个字符是否在s2中 if i in s2: # replace 表示替换; # 将s1中与s2中相同的所有字符,替换为空字符 s1 = s1.replace(i,'') print(s1)
python集合综合练习
1.地铁站编号和站名对应关系如下:
1=朱辛庄
2=育知路
3=平西府
4=回龙观东大街
5=霍营
//....
遍历打印(可以不按顺序打印):
第10站: 森林公园南门
第6站: 育新
第12站: 奥体中心
第13站: 北土城
//...
2.计算地铁票价规则:
总行程 3站内(包含3站)收费3元,
3站以上但不超过5站(包含5站)的收费4元,
5站以上的,在4元的基础上,每多1站增加2元,
10元封顶;
3.打印格式(需要对键盘录入的上车站和到达站进行判断,如果没有该站,提示重新输入,直到站名存在为止):
注意:每站需要2分钟
请输入上车站:
沙河
您输入的上车站:沙河不存在,请重新输入上车站:
上地
您输入的上车站:上地不存在,请重新输入上车站:
朱辛庄
请输入到达站:
沙河
您输入的到达站:沙河不存在,请重新输入到达站:
西二旗
您输入的到达站:西二旗不存在,请重新输入到达站:
西小口
从朱辛庄到西小口共经过6站收费6元,大约需要 12分钟
st = """十三号街站 05:30 23:00 —— —— 中央大街站 05:31 23:01 06:28 23:47 七号街站 05:33 23:03 06:26 23:45 四号街站 05:36 23:06 06:24 23:42 张士站 05:38 23:08 06:21 23:40 开发大道站 05:41 23:11 06:19 23:37 于洪广场站 05:43 23:13 06:16 23:35 迎宾路站 05:46 23:16 06:14 23:33 重工街站 05:48 23:18 06:11 23:30 启工街站 05:51 23:21 06:09 23:28 保工街站 05:53 23:23 06:07 23:26 铁西广场站 05:55 23:25 06:04 23:23 云峰北街站 05:58 23:28 06:02 23:21 沈阳站 06:01 23:31 06:00 23:18 太原街站 06:03 23:33 06:16 23:16 南市场站 06:05 23:35 06:13 23:13 青年大街站 06:07 23:37 06:11 23:11 怀远门站 06:10 23:40 06:09 23:09 中街站 06:13 23:43 06:06 23:06 东中街站 06:15 23:45 06:04 23:04 滂江街站 06:17 23:47 06:01 23:01 黎明广场站 —— —— 06:00 23:00""" lst = st.split() llsstt = list(filter(lambda x : '站' in x,lst)) print(llsstt) while True: upstation = input('请输入上车站:') if upstation not in llsstt: print(f'您输入的上车站:{upstation}不存在,请重新输入上车站') upstation_idx = llsstt.index(upstation) downstation = input('请输入下车站:') if downstation not in llsstt: print(f'您输入的下车站:{upstation}不存在,请重新输入下车站') else: downstation_idx = llsstt.index(downstation) if downstation_idx < upstation_idx: print('下车站必须在上车站之后') else: break diff = downstation_idx - upstation_idx price = 0 if diff <= 3: price = 3 elif diff <= 5: price = 4 else: price = 4 + (diff - 5)*2 if price > 10: price = 10 print(f'从{upstation}到{downstation}共经过{diff}站收费{price}元,大约需要{diff*2}分钟')
python函数综合练习
1.编写一个函数cacluate, 可以接收任意多个数,返回的是一个元组.
元组的第一个值为所有参数的平均值, 第二个值是大于平均值的所有数.
运行结果:
# 1.定义函数; *args:可变参数 def cacluate(*args): # 2.计算平均值; args的数据类型为元组,sum求和 average = sum(args) / len(args) # 3.将所有大于平均值数的值存入列表 list=[] for i in args: if i > average: list.append(i) # 4.将平均值和列表元素存入元组 tuple=(average,list) return tuple print(cacluate(1,1,2,3,4))
2.编写一个函数, 接收字符串参数, 返回一个元组,
元组的第一个值为大写字母的个数, 第二个值为小写字母个数.
例如
输入:'hello WORLD'
输出:(5,5)
# 直接在函数里print输出,在调用函数时只能打印不能使用 # 如果想要使用函数里的变量值,此时需要在定义函数时用return返回函数值 def fun(c): # 记录大写字母个数 upper = 0 # 记录小写字母个数 lower = 0 # 统计大小写字母的个数 for i in c: if i.isupper(): upper += 1 # 注意:不能用else,因为字符串之间有空格 if i.islower(): lower += 1 tuple = (upper,lower) # 函数返回值 return tuple # 此时直接调用函数将不会有输出值,必须用print输出 print(fun(input('请输入字符串:')))
3.编写函数, 接收一个列表(包含30个1~100之间的随机整形数)
和一个整形数k, 返回一个新列表.
函数需求:
- 将列表下标k之前对应(不包含k)的元素逆序;
- 将下标k及之后的元素逆序;
# 导入生成随机数的包 import random # 定义空列表 list = [] # 生成30个随机数 for i in range(30): num = random.randint(1,100) # 将生成的随机数添加到列表中 list.append(num) # 打印原始列表 print(list) # 定义函数 def fun(list,k): # k表示下标 if k < 0 or k >= len(list): print('error key') else: # [:k] k之前的元素 [::-1] 逆序 + 连接 return list[:k][::-1] + list[k:][::-1] print(fun(list,3))
4.模拟轮盘抽奖游戏
轮盘分为三部分: 一等奖, 二等奖和三等奖;
轮盘转的时候是随机的,
如果范围在[0,0.08)之间,代表一等奖,
如果范围在[0.08,0.3)之间,代表2等奖,
如果范围在[0.3, 1.0)之间,代表3等奖,
模拟本次活动1000人参加, 模拟游戏时需要准备各等级奖品的个数.
import random # 定义(得奖情况)字典 rewardDict ={'一等奖':(0,0.08),'二等奖':(0.08,0.3),'三等奖':(0.3,1.0)} # 判断用户是否得奖 def rewardfun(): num = random.random() # 遍历key-value for k,v in rewardDict.items(): if num >= v[0] and num < v[1]: return k # 定义空字典 resultDict = {} # 将得奖记录添加到字典中,记录1000人玩游戏的得奖情况 for i in range(1000): # 将函数的返回值赋给reskey reskey = rewardfun() # print(reskey) if reskey not in resultDict: # 增加元素 resultDict[reskey] = 1 else: resultDict[reskey] += 1 # 遍历输出字典的 key-value值 for k,v in resultDict.items(): print(k,'---->',v)
5.题目需求:
对于一个十进制的正整数, 定义f(n)为其各位数字的平方和,如:
f(13) = 12 + 32 = 10
f(207) = 22 + 02 + 72 = 53
下面给出三个正整数k,a, b,你需要计算有多少个正整数n满足a<=n<=b,
且kf(n)=n
输入:
第一行包含3个正整数k,a, b, k>=1, a,b<=10*18, a<=b;
输出:
输出对应的答案;
范例:
输入: 51 5000 10000
输出: 3
k=51 a=5000 b=10000 7293 143 7854 154 7905 155 3
# 1.接收用户输入 k = int(input('k=')) a = int(input('a=')) b = int(input('b=')) # 2.定义函数,计算f def fun(c): f = 0 for i in str(c): f += int(i)**2 return f # fun(207) # 定义计数器 count = 0 # 3.统计满足条件的n的个数 for n in range(a,b+1): if k * fun(n) == n: print(n,fun(n)) count += 1 # 打印个数 print(count)