文章目录

  • 一、函数的返回值
  • 二、函数的作用域
  • 2.1局部变量
  • 2.2 全局变量
  • 三、递归函数
  • 1. 什么是递归函数
  • 2. 递归的特点
  • 3. 4个步骤,写出一个递归函数
  • 3.1 第一步,定义函数功能
  • 3.2 第二步,找到终止条件
  • 3.3 第三步,甩锅
  • 3.4 第四步,反甩锅
  • 3.5 应用:3以内数字累加和
  • 练习题 - 定义一个函数用来检查字符串是否回文字符串


一、函数的返回值

  • 函数的返回值就是函数执行以后返回的结果。
  • return的作用是退出函数并返回函数的返回值,任何时候,只要执行了return语句就一定会退出函数。
  • 函数的返回值可以直接使用,也可以通过一个变量进行接收函数的返回值,一般用变量接收的方法。
def fn():
    # return后面可以跟任意对象
    return 123
    # return 'haha'
    # return [4,5,6]
    # return {'name':'jerry'}
    a = 1
r = fn()
print(r)  # 123
print(fn())  # 123

一个函数没有写return ,或者仅仅写了一个return 那么就相当于 return None, 输出为None就是没有返回值。

def fn():
    print('hello world')

res = fn()
print(res)
  • 尽管函数fn没有使用return语句,但仍然会有返回值,这种情况下,函数默认返回None。
  • python的函数允许一次返回多个结果
def fn():
    return 1, 2

res = fn()
print(res, type(res))  # (1, 2) <class 'tuple'>
  • 函数一次返回多个结果时,是以元组的形式返回的。
  • return后面可以连接列表、元组或字典,以返回多个值。
  • 如果函数里没有任何数据需要返回,但需要提前结束,也可以使用return。
def fn2():

    print('haha')
    return
    print('heihei')

r = fn2()  # haha
print(r)  # None

在函数中,return后面的代码都不会执行。return一旦执行函数自动结束。

二、函数的作用域

函数作用域在函数调用时创建,在调用结束时销毁。

函数每调用一次就会产生一个新的函数作用域,在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问

函数的作用域指的是函数生效的范围,主要分为两类:局部变量全局变量

2.1局部变量

所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效。

def testA():
    a = 100

    print(a)


testA()  # 100
print(a)  # 报错:name 'a' is not defined

变量a是定义在testA函数内部的变量,在函数外部访问则立即报错。

局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量。

2.2 全局变量

所谓全局变量,指的是在函数体内、外都能生效的变量。

思考:如果有一个数据,在函数A和函数B中都要使用,该怎么办?

答:将这个数据存储在一个全局变量里面。

# 定义全局变量a
a = 100


def testA():
    print(a)  # 访问全局变量a,并打印变量a存储的数据


def testB():
    print(a)  # 访问全局变量a,并打印变量a存储的数据


testA()  # 100
testB()  # 100

思考:testB函数需求修改变量a的值为200,如何修改程序?

a = 100


def testA():
    print(a)


def testB():
    a = 200
    print(a)


testA()  # 100
testB()  # 200
print(f'全局变量a = {a}')  # 全局变量a = 100

思考:在testB函数内部的a = 200中的变量a是在修改全局变量a吗?

答:不是。观察上述代码发现,最后一行得到a的数据是100,仍然是定义全局变量a时候的值,而没有返回

testB函数内部的200。综上:testB函数内部的a = 200是定义了一个局部变量。

思考:如何在函数体内部修改全局变量?

a = 100


def testA():
    print(a)


def testB():
    # global 关键字声明a是全局变量
    global a
    a = 200
    print(a)


testA()  # 100
testB()  # 200
print(f'全局变量a = {a}')  # 全局变量a = 200

如果你希望在函数内部修改全局变量的时候,则需要使用global关键字,来声明变量。

三、递归函数

1. 什么是递归函数

  • 递归是一种解决问题的思想,它和循环很像,整体思想是将一个大问题分解为一个一个的小问题,直到问题无法分解时,再去解决问题。
  • 从前有座山,山里有座庙,庙里有个老和尚在给一个小和尚讲故事,讲什么故事呢?从前有座山,山里有座庙,庙里有个老和尚在给一个小和尚讲故事,讲什么故事呢?…递归就类似这个故事一样。
  • 递归函数是一种特殊的函数,函数内部调用函数自身。

2. 递归的特点

递归式的函数需要2个条件:

  1. 基线条件
    问题可以被分解为最小的问题,当满足基线条件时,递归就不在执行了,就是必须有有一个出口
  2. 递归条件
    将问题可以继续分解的条件, 函数内部自己调用自己

下面是一个函数例子改造成递归函数,你可以对比他们之间的区别。

def my_print(content, count):
    for i in range(count):
        print(content)

my_print('ok', 2)

改造成递归函数后

def my_print(content, count):
    print(content)
    if count == 1:
        return
    my_print(content, count-1)

my_print('ok', 2)

在改造后的递归函数中,会再次调用my_print函数自身。你不禁会担忧,这样自身调用自身,岂不是要形成死循环?没错,会形成死循环,因此递归函数一定要有一个递归终止的条件,在本示例中,递归终止的条件是count=1,当这个条件满足时,就会执行return 语句,函数退出。

3. 4个步骤,写出一个递归函数

递归函数对初学者来说,是无法回避的噩梦。刚刚对程序顺序执行有了一定理解后,突然间告诉你函数可以调用函数自身,近似无限循环的递归调用让你深陷其中无法自拔。

编程,既是一门知识,也是一门手艺,你可以自学知识,但手艺很难自学,没有长时间的经验积累,没有一次次的试错和总结,你的技能就无法得到提升,所以,手艺,需要有人传帮带。

咱们以最简单的计算阶乘为例,将完成递归函数归纳为4个步骤

  1. 定义函数功能
  2. 找到终止条件
  3. 甩锅
  4. 反甩锅

3.1 第一步,定义函数功能

# 创建一个函数 求任意数的阶乘
def fn(n):
    """
    :param n:
    :return:
    """

3.2 第二步,找到终止条件

所有的递归函数,一定会有终止条件,如果不符合这个要求,那么就会进入死循环。函数的功能是计算阶乘,阶乘的终止条件是什么呢? 是1啊,1的阶乘是1,你不能计算0的阶乘,1是最小的可以求阶乘的整数,现在,假设调用函数传参n为1,代码该怎么写呢?

# 创建一个函数 求任意数的阶乘
def fn(n):
    """
    :param n:
    :return:
    """
    # 参数n 要求阶乘的数字

	 # 1 基线条件
     # 判断如果n为1的时候,就是它本身就不需要递归了,就是必须有出口
    if n == 1:
        return 1

函数的功能是计算n的阶乘,如果n等于1,直接返回1就好了

3.3 第三步,甩锅

如果n不是1,该怎么办呢?答案很简单,甩锅,这就是说,现在你搞不定这个事情了,那你可以把锅帅给别人啊,你找到小明,告诉他: 老师让我计算n的阶乘,你现在计算n-1的阶乘,把结果告诉我,要快,不然老师生气了。

你看,把锅甩给了小明,小明如果能算出来n-1的阶乘,你把他的答案乘以n,不就是n的阶乘了么,如果小明算不出来,你对老师也能有交代,是小明的过错,这就叫甩锅,这就是函数的递归调用

def fn(n):
    """
    :param n:
    :return:
    """
    # 参数n 求阶乘的数字

	 # 1 基线条件
     # 判断如果n为1的时候,就是它本身就不需要递归了,就是必须有出口
    if n == 1:
        return 1

    s = fn(n-1)   # 等待小明的结果

3.4 第四步,反甩锅

你把锅甩给小明,小明也不傻,他又把锅甩给了小刚,小刚表示很无辜,但事情还是要做,于是又甩给了小红,就这样,一个接着一个的甩,但是要注意,总会有甩不出去的时候,最后,锅甩到了小芳这里,小芳是个好姑娘,聪明乖巧,到她这里,需要计算1的阶乘,小芳心想,甩不出去了,而且也不用甩啊,1的阶乘就是1啊,多简单。

于是,开始了第四个步骤,反甩锅,1的阶层等于1,小芳心想,我已经告诉你答案了,剩下的事情你们处理吧,这口锅沿着一开始的路线反向的甩了回来,每个人都得到了之前自己甩锅的人的答案,现在小明把n-1的阶乘告诉给你,你应该怎么办呢,你应该把结果乘以n,然后return这个结果,最终完成了老师的要求

def fn(n):
    """
    计算n的阶乘
    :param n:
    :return:
    """
     # 参数n 要求阶乘的数字
     
	 # 1 基线条件
     # 判断如果n为1的时候,就是它本身就不需要递归了,就是必须有出口
    if n == 1:
        return 1

#    s = fn(n-1)
#    return s*n
     # 2 递归条件8 * 7!(上面的代码可以直接简化)
    return n * fn(n-1)


print(fn(8))

上面的代码,没有一个字符超出你的学习范围,就是知识;以怎样的逻辑组织代码,理解代码结构,这就是手艺

定义一个函数 来为任意数字做任意幂运算 n ** i

# 10 ** 5 = 10 * 10 ** 4
#  10 ** 4 = 10 * 10 ** 3
# .....
# 10 ** 1 = 10


def fn(n,i):
    """

    :param n:     参数n 要做幂运算的数字
    :param i:     参数i 要做幂运算的次数
    :return:
    """

    # 1 基线条件
    if i == 1:
        return n
    #  2 递归条件 10 ** 5 = 10 * 10 ** 4
    return n * fn(n,i-1)

print(fn2(5,6))
print(5 ** 6)

3.5 应用:3以内数字累加和

# 3 + 2 + 1
def sum_numbers(num):
    # 1.如果是1,直接返回1 -- 出口
    if num == 1:
        return 1
    # 2.如果不是1,重复执行累加并返回结果
    return num + sum_numbers(num-1)


sum_result = sum_numbers(3)
# 输出结果为6
print(sum_result)
  • 执行结果

Python中函数return位置 python函数return的作用_全局变量

练习题 - 定义一个函数用来检查字符串是否回文字符串

def fn(s):
    """判断回文数,递归法"""
    if len(s) < 2:
        return True
    if s[0] == s[-1]:
        return fn(s[1:-1])
    else:
        return False


name1 = '11'
name2 = '1234'
print(fn(name1))
print(fn(name2))