十四、python基础:函数的进阶用法
列举一些函数,用来加深一下对函数的印象,其中斐波那契数列的相关计算是使用了递归算法。
一、函数的执行顺序;
二、增加函数灵活性;
三、把函数当参数传递;
四、集合关键字参数;
五、斐波那契数列(兔子数列);
六、switch函数。
一、函数的执行顺序;
def test_1():
print("-" * 50)
def test_2():
print("*" * 50)
test_1()
print("+" * 50)
test_2()
先调用了test_2,在test_2中又调用了test_1
二、增加函数灵活性;
在函数内调用另一个函数。
def print_line_1(char, times):
print(char * times)
print_line_1("+",50)
def print_line_2():
row = 0
while row < 5:
print_line_1("*", 50)
row += 1
print_line_2()
三、把函数当参数传递;
def test_2(func):
print("这是test_2")
func()
def test_3():
print("这是test_3")
test_2(test_3)
四、收集位置参数和关键字参数;
#使用*可以收集位置参数
#使用**可以收集关键字参数,返回的是关键字元组
def print_kwargs(*args, **kwargs):
for i in kwargs.items():
print(i)
for i in args:
print(i)
print_kwargs("a", arg1='beef', arg3='bordeaux')
五、斐波那契数列(兔子数列);
斐波那契数列又因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。
具体问题是,假设兔子在出生第1个月没有繁殖能力,第2个月也没有繁殖能力,到了第3个月就有繁殖能力了,并且1对兔子每个月能生出1对小兔子来。假设所有兔子都不死,那么10个月以后总共有多少对兔子,11个月呢?n个月呢?如何使用函数打印出一个斐波那契数列?
斐波那契数列手写出来就是:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 ...
先思考一下这个数列有什么特征?
特征就是:它的第1和第2个数都是1,但从第3个数开始,每个数都是它前2个数之和。
我们先不计算10个月后有多少兔子,想一下当兔子数量还没达到200之前,这个数列怎么用函数来打印输出:
分析一下:
1、想要用函数不断打印出数字,可以使用循环;
2、既然有循环,我们就需要给它指定开始打印的条件,和结束打印的条件,很明显第1个月和第2个月的1都可以作为起始条件,200只可以作为终止条件;
3、如果我们在整个循环中只使用一个变量,貌似无法满足条件,因为当下一次打印时,我们并不知道它跟上一个值的差距是多大,无法通过设定差值来重复打印。所以需要至少2个变量。
4、既然我们已经知道了第1和第2个数肯定是1的了,那就可以让变量a=1,b=1。并且从已有的条件来看,我们还可以假设第3个数就是c,并且它的值会等于a+b的值。
于是,我们可以第1次就打印a的值,打印完之后把b的值给到a,让它接着打印a的值,但同时为了接下来能够继续,c的值就要给到b了。
其实从这个逻辑来看,我们就相当于每次只是打印整个数列的开头,但是每打印一次,就让后面的数字都往前挤一位。
于是兔子数列可以这么写:
#输出兔子数在200以内的兔子数列
a, b = 1, 1
while a < 200:
print(a)
c = a + b
a = b
b = c
上面的写法还能简化一下:
#输出兔子数在200以内的兔子数列
a, b = 1, 1
while a < 200:
print(a)
a, b = b, a+b
输出结果是:
那么接下来怎么计算出第n个月兔子的数量呢?
按照数列来看,第n个月的值总是会等于第(n-1)个月的值加上第(n-2)个月的值。
所以假设当前的月份是第7个月,我们想要知道这个月的数量,必须先知道第5和第6个月的数量,而第6个月同样也是需要问一下第5和第4个月的数量。
那么就可以一层一层问下去,直到我们问到了第1和第2个月数量都是1只,它们都是确定的值了,就不需要再继续问下去了。这时候就可以一层一层再反馈回来告诉我们,最终我们就能知道当前月份的数量了。
这个逻辑用程序表达出来就是下面这样:
# 斐波那契数列(兔子数列)迭代器,递归算法
def fib(x):
if x == 2 or x == 1:
return 1 # 注意返回的是1,由于第一第二个月都是一只兔子
return fib(x-1) + fib(x-2)
print(fib(7)) # 打印输出的结果是13
它的特点是返回值需要调用函数本身,所以会形成一个循环迭代,并且通过让参数的值每一次调用都会减少,直到参数值减少到1和2的时候,给它返回一个确定的数值,来控制程序的结束。
这个其实是一个迭代器,当用户参数输入7的时候,一开始进去如果不满足x=2或x=1,它直接进入return,返回前2个月的和,接着继续往下迭代,当遇到x=2的时候,就遇到函数的出口了。
跟兔子数列类似的还有另一个问题
# N阶楼梯上楼问题:一次可以走两阶或一阶,问有多少种上楼方式?
# 分析:如果只有1阶,只有1种走法,如果有2阶,那就是2种走法
def fic(n):
if n == 1 or n == 2:
return n
elif n >= 3:
return fic(n - 1) + fic(n - 2)
else:
return -1
print(fic(5)) # 打印输出的结果是8
六、自定义一个switch函数。
python中并没有switch函数,但是我们可以自己定义一个。
什么是switch函数?
在excel函数中,我们如果需要批量替换掉多个值,并且每个值会对应另一个值,就好比原先表格上,班级写的是class1,class2,class3等等十几个,现在要把它替换成”班级1“,”班级2“, ”班级3“等等,你可以选择手动一个个去替换,比较麻烦。比较快捷的是使用switch进行批量替换,只需要写个函数。
例如:在excel使用这个switch函数,可以实现将所有’Class1’替换成”一班“,‘Class2’替换成”二班“等等。
switch($$$,'Class1','一班','Class2','二班','Class3','三班','Class4','四班')
但在python中没有现成的switch函数,我们怎么实现这种类型的函数?
假设我们有一个需求,写一个函数给用户调用,让用户可以随意传入2个值和一个运算符,函数会自动根据用户输入的运算符判断用户想要执行的是什么运算,接着计算出结果。
方法一:你当然可以使用if … elif…else去判断运算符,调用不同的计算公式,但这样如果有很多种情况的话,你需要写非常多的分支结构。
方法二:比较灵活的方法是自己构造一个switch函数来。
可以像下面这么写,它实现的关键是:
通过字典的映射关系,让用户传入的运算符跟对应执行的函数名建立一一对应关系。
def jia(x, y):
print(x + y)
def jian(x, y):
print(x-y)
def cheng(x, y):
print(x * y)
def chu(x, y):
print(x / y)
operator = {'+': jia, '-': jian, '*': cheng, '/': chu}
def f(x, o, y):
operator.get(o)(x, y)
f(3, '+', 2)
f(3, '-', 2)
operator.get(o)是对operator这个字典通过调用get()获取o这个键对应的值,获取到的会是一个函数名。
后面跟个(x, y),括号就是对获取到的函数进行调用,并且传入2个参数是x和y。