专栏首页A2DataDay9.函数进阶

Day9.函数进阶

例题引导:

一个由元组构成的列表:a = [('b',3), ('a',2), ('d',4), ('c',1)]

要求:使用lambda表达式和函数sorted(),分别按照元组第一个元素排序(即abcd排序),按照元组第二个元素排序(即1234排序),输出相应的列表结果。

要点:了解lambda表达式和排序函数sorted()用法

参考答案:

a = [('b',3), ('a',2), ('d',4), ('c',1)]

print(sorted(a, key=lambda x:x[0]))

print(sorted(a, key=lambda x:x[1]))

学习引导:

  • 匿名函数
  • 函数的返回值
  • 函数的说明文档
  • 函数的嵌套
  • 变量作用域
  • 函数递归

匿名函数

  • python可以使用lambda来创建匿名函数
  • 所谓匿名,即不再使用def这样的标准语句来专门定义函数
  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda中封装有限的逻辑进去。
  • lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间中的参数。
  • 有名函数的定义规则为【def+函数名+参数】;而匿名函数则是用【lambda+参数+表达式】的方式定义函数

lambda的语法只包含一个语句,格式如下:

lambda [arg1[,arg2,...,argN]]:expression

下面用几个例子对两种函数进行对比,以便大家理解。

用def格式写

#用def格式写
def func(x,y):
    return x*y
func(2,3)
#6

用匿名函数写

#用匿名函数写
func=lambda x,y:x*y
func(3,4)
#12

从上面例子可以看出匿名函数相较标准函数的优点有

  • 不用取名称,因为给函数取名是比较头疼的一件事,特别是函数比较多的时候可以直接在使用的地方定义,如果需要修改,直接找到修改即可,方便以后代码的维护工作
  • 语法结构简单

函数的返回值

return[表达式]语句用于退出函数,选择性的向调用方返回一个表达式。不带参数值的return语句返回None。

下面演示一下return语句的用法:

def sum(arg1,arg2):
    "返回两个参数的和"
    total=arg1+arg2
    print('函数内:',total)
    return total

#调用sum函数
total=sum(23,32)
print('函数外:',total)
#函数内:55
#函数外:55

函数的说明文档

  • 定义:即对函数进行简单的解释说明(一般对参数和返回值进行说明)
  • 作用:方便他人理解和自己日后的复读

语法结构如下:

def 函数名(参数):
    '函数的说明文档内容'
    函数体
    return 返回值

对于函数的内置函数,可以使用help()函数查看其内置文档。

函数的嵌套

在函数中再定义一个函数

语法结构如下:

def outer():
    def inner():
        print('inner')
    print('outer')
    inner()
outer()
# inner()  #该句会报错
#outer
#inner

一个案例

#一个案例
def outer():
    str='Hello World'
    def inner():
        print(str)
    return inner

info=outer()
info()      
#Hello World

变量作用域

一个标识符的可见范围,就是标识符的作用域。一般常说的是变量的作用域。

  • 函数中的局部作用域:local
  • 嵌套函数中父级函数的局部作用域:enclosing
  • 全局作用域:global
  • 系统内置的变量:如 int、str、list 等关键字
  • 局部变量:在某个函数内部定义,作用在函数内部。生命周期:从变量被创建开始到函数结束死亡。
  • 全局变量:定义在.py模块内部,作用在整个.py模块。生命周期:从变量被创造开始到.py模块结束死亡。

案例演示

def Demo1():
    num=1
    print(num)
    
Demo1()
print(num)    #该句报错。因为num是局部作用,所以在函数外面是找不到num这个变量的。
#1
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-56-d3aaf0ba8dea> in <module>
      5 
      6 Demo1()
----> 7 print(num)
NameError: name 'num' is not defined

对上例的解释

num = 0
def Demo1():
    num = 1
    print("在demo1中的结果:",num)
def Demo2():
    print("在demo2中的结果:",num)

Demo1()
Demo2()
#在demo1中的结果: 1
#在demo2中的结果: 0

从结果可以看出,我们在demo1中num = 1,只在demo1内部起作用,而全局变量num仍然是0;因为在python中,在函数内部改变全局变量的值,会默认的在函数内部创建一个新的变量,全局变量并没有改变。 要想要改变全局变量的值,需要在函数内部用global声明。

现修改上面代码如下:

num = 0
def Demo1():
    global num
    num = 1
    print("在demo1中的结果:",num)
def Demo2():
    print("在demo2中的结果:",num)

Demo1()
Demo2()
print("在函数外面中的结果:",num)
#在demo1中的结果: 1
#在demo2中的结果: 1
#在函数外面中的结果: 1

还有一种情况是当全局变量是可变数据类形,我们可以通过修改可变数据类型的方法,修改可变类型的内容,从而实现修改全局变量。(这里因为可变数据类型改变时,会在内存中改变数据的值)

num_list = [1,2,3]

def Demo1(demo1_list):
    demo1_list.append(4)
    print("在demo1中的结果:",demo1_list)

def Demo2():

    print("在demo2中的结果:",num_list)

Demo1(num_list)
Demo2()

print("在函数外面中的结果:",num_list)
#在demo1中的结果: [1, 2, 3, 4]
#在demo2中的结果: [1, 2, 3, 4]
#在函数外面中的结果: [1, 2, 3, 4]

列表 += 与 + 的区别

#+:

num_list = [1,2,3]

def Demo1(demo1_list):
    demo1_list = demo1_list + [4,5,6]
    print("在demo1中的结果:",demo1_list)

def Demo2():
    print("在demo2中的结果:",num_list)

Demo1(num_list)
Demo2()

print("在函数外面中的结果:",num_list)
#在demo1中的结果: [1, 2, 3, 4, 5, 6]
#在demo2中的结果: [1, 2, 3]
#在函数外面中的结果: [1, 2, 3]

#+=:

num_list = [1,2,3]

def Demo1(demo1_list):
    demo1_list +=  [4,5,6]
    print("在demo1中的结果:",demo1_list)

def Demo2():

    print("在demo2中的结果:",num_list)

Demo1(num_list)
Demo2()

print("在函数外面中的结果:",num_list)
#在demo1中的结果: [1, 2, 3, 4, 5, 6]
#在demo2中的结果: [1, 2, 3, 4, 5, 6]
#在函数外面中的结果: [1, 2, 3, 4, 5, 6]

因为: 对于+号操作,可变对象和不可变对象调用的都是add操作 对于+=号操作,可变对象调用add,不可变对象调用的是iadd(不可变对象没有iadd) iadd是原地修改

函数递归

  • 定义:在调用一个函数的过程中直接或间接的调用该函数本身,称之为递归调用。
  • 递归调用最多能调用999层。
#基础模型一
def func():
    print('from func')
    func()    #直接调用自身
    
func()
    
#基础模型二
def func():
    print('from func')
    bar()    #间接调用自身

def bar():
    print("from bar")
    func()

func()

虽然以上两中方式为函数递归的基础模型,但往往不能直接这样使用。因为没有一个函数的结束条件,仅仅相当于一个死循环。 递归分为两个重要的阶段: 递推+回溯

  • 递推:函数不断减少问题规模直至最终的终止条件。
  • 回溯:拿到最终明确的值后,返回给上次调用进行处理,直至初始层。

下面为一个练习题:解决年龄问题,求出Jack的年龄

"""
Jack 他比小王 大两岁。4   age(3) + 2
小王 他比大枫 大两岁。3   age(2) + 2
大枫 他比美丽 大两岁。2   age(1)  + 2
美丽:我今年18.         1   18
"""

def age(n):
    if n == 1:
        return 18
    else:
        return age(n-1) + 2

print(age(4))
#24

注意在Python:     1、递归调用必须有一个明确的结束条件     2、在python中没有尾递归优化,递归调用的效率不高     3、进入下一次递归时,问题的规模必须降低 再来一个例子输入任意一个数,让其除以2,直到不能再除

def  cal(num):
    if  num%2==0:#先判断能不能整除
        num=num//2
        return cal(num)
    else:
        return num
print(cal(8))
#1

小作业:

1.定义并调用两个函数fib(n)PrintFN(m,n),输出指定的斐波那契数信息(斐波那契数列:1,1,2,3,5,8,...不了解的自行百度)。函数要求:

fib(n):返回斐波那契数列的第n个值

PrintFN(m,n):用列表返回[m, n]中的所有斐波那契数。

例如输入:20 100 6,输出:

fib(6) = 13
4

2.解决汉诺塔问题(汉诺塔规则请自行百度):

有ABC三根柱子,将A柱上的n个盘子移动到C柱。控制台输入盘子个数n,输出移动的所有步骤,格式样例“A-->C”。

3.假设你正在爬楼梯。需要 n 阶你才能到达楼顶(给定n为正整数),每次可以爬 1 或 2 个台阶。编写函数,返回有多少种不同的方法可以爬到楼顶。

def climbStairs(n):
    dp = []
    dp.append(1) # 初始状态,只有1阶的时候有一种走法
    dp.append(2) # 有2阶的时候有两种走法
    if n==1:        #终止条件
        return 1        
    if n==2:        #终止条件
        return 2
    for i in range(2,n):
        dp.append(dp[i-1]+dp[i-2])      #递归
        
    return dp[-1]

4.以下代码是否能执行,原因是?如何修改?

def fun1():
    x = 3
    def fun2():
        x *= x
        return x
    return fun2()

print(fun1())

5.写出以下代码的执行结果:

def fun2():
    print(2)
    def fun3():
        print(6)
    print(4)
    fun3()
    print(8)
print(3)
fun2()print(5)

本文分享自微信公众号 - DataScience(DataScienceTeam),作者:DataScience

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何打败坑神 Null

    在现实工作中,经常会遇到一个神奇的字眼 “NULL",这是啥?它有啥用?啥时候用?怎么用?着实令人头秃!!!

    DataScience
  • NumPy入门指南(二) | Day2

    数组的索引就是列表中的下标,来表明数组中元素的顺序位置;通过查询索引可以获取到想要的元素, 切片是截取到需要元素的集合。

    DataScience
  • NumPy入门指南(一) | Day1

    今明两天我们主要学习NumPy,NumPy是用Python做数据分析时不可或缺的一个库,想知道它怎么使用吗?快往下看吧!(ps:课程内容较多,大家坚持住哦!)

    DataScience
  • Python闭包函数和装饰器

    1.概念:在一个外函数中定义了一个内函数,内函数运用了外函数的临时变量,并且外函数的返回值是内函数的引用 示例代码:演示函数嵌套和闭包。

    潇洒坤
  • Python基础(06)函数

    一年一度的1024又来了,1024最初源自于一个论坛,他的回帖机制是,新用户发过帖之后,过1024秒之后才能再发一帖。

    PM小王
  • 实验四 Python函数编程实验

    函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段,它能够提高应用的模块性和代码的重复利用率。Python定义函数使用def关键字,格式如下:

    背雷管的小青年
  • Python3匿名函数字典排序、生成式与

    参数类型: 我们经常在看别人的代码中,经常出现def(*args,**kwargs)这样的表现形式;

    py3study
  • Python装饰器入门教程 | 新手教程

    昨天简单聊了下Flask的学习感想,然后分享了一些Flask的学习方式与视频。其中提到在学习Python Web前,请先将python基础及装饰器等知识有一个了...

    马哥Python
  • python3–装饰器

    老七Linux
  • Python|有趣的shuffle方法

    Pythonrandom的“shuffle方法随机化序列项”是我们在学习中会经常遇到的一个知识点,今天我们就来简单的学习一下吧!

    算法与编程之美

扫码关注云+社区

领取腾讯云代金券