十四、python基础:函数的一些进阶用法

十四、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个月呢?如何使用函数打印出一个斐波那契数列?

斐波那契数列手写出来就是:

1123581321345589144 ...

先思考一下这个数列有什么特征?

特征就是:它的第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。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值