Python函数

文章目录

  • 函数的概念
  • 函数的定义格式
  • 函数的调用格式
  • 函数的调用方式
    • 链式调用
    • 嵌套调用
    • 递归调用
  • 默认参数与变长参数
    • 默认参数
    • 变长参数
  • 变量作用域

函数的概念

编程中的函数,是一段可以被重复使用的代码片段,使用函数能够减少冗余的代码。比如:

# 1.求1-100的和
sum = 0
for i in range(1, 101):
    sum += i
print(f'sum = {sum}')  # 5050

# 2.求300-400的和
sum = 0
for i in range(300, 401):
    sum += i
print(f'sum = {sum}')  # 35350

# 3.求1-1000的和
sum = 0
for i in range(1, 1001):
    sum += i
print(f'sum = {sum}')  # 500500

上述几组代码的处理逻辑都是类似的,这种情况就可以把重复的代码提取出来,封装成一个函数,需要求和时直接调用该函数即可。比如:

def calcSum(begin, end):
    theSum = 0
    for i in range(begin, end + 1):
        theSum += i
    return theSum


print(calcSum(1, 100))    # 5050
print(calcSum(300, 400))  # 35350
print(calcSum(1, 1000))   # 500500

这时就可以明显看到,重复的代码已经被消除了。

函数的定义格式

函数的定义格式

函数的定义格式如下:
Python函数_第1张图片
注意事项:

  • 一个函数可以有一个或多个形参,也可以没有形参。
  • 一个函数中可以有一个或多个return语句,执行到return语句时函数会立即执行结束,回到调用位置。
  • Python是动态类型语言,函数的形参和返回值都不必指定类型,因此一个函数可以支持多种不同类型的参数。

多个返回值

此外,Python中的一个函数可以有一个或多个返回值,当有多个值需要返回时,使用,来分隔这多个返回值。比如:

def getSumAndDif(x, y):
    return x + y, x - y


a = 10
b = 20
sum, dif = getSumAndDif(a, b)
print(f'{a} + {b} = {sum}, {a} - {b} = {dif}')

Python中一个函数能返回多个值,本质就是多元赋值所支持的。如果函数调用者只想关注该函数的部分返回值,那么可以使用_来忽略不想要的返回值。比如:

_, dif = getSumAndDif(1, 2)
print(dif)

函数的调用格式

函数的调用格式

函数的调用格式如下:
在这里插入图片描述
注意事项:

  • 函数必须先定义再使用,函数定义后并不会执行函数体的内容,必须要被调用后才会执行。

传参方式

调用函数时可以根据函数的形参列表,将实参列表中的实参按照顺序依次传给对应的形参。比如:

def Dif(x, y):
    return x - y


print(Dif(10, 20))  # -10

此外,也可以通过关键字参数来调整传参的顺序,显式指定当前实参传递给哪个形参。比如:

print(Dif(y=10, x=20))  # 10

函数的调用方式

链式调用

链式调用指的是把一个函数的返回值,作为调用另一个函数时的参数进行传入。

例如,下面代码中调用print函数时,将Add函数的返回值作为了参数。

def Add(x, y):
    return x + y


print(Add(10, 20))  # 30

嵌套调用

嵌套调用指的是在一个函数的函数体内部,调用了其他函数。

例如,下面代码中的test函数内部调用了print函数。

def test():
    print('do something...')
    print('do something...')
    print('do something...')


test()

递归调用

递归掉是嵌套调用的一种特殊情况,即在一个函数内部嵌套调用自己。

例如,下面的factor函数可以用来求一个数的阶乘。

def factor(n):
    if n == 1:
        return 1
    return n * factor(n - 1)

在factor函数内部又嵌套调用了factor函数,这就是递归调用。

递归调用与返回的过程

以求3的阶乘为例,factor函数的递归调用与返回过程如下图:
Python函数_第2张图片
即一层层进行递归调用,当满足递归结束条件时再逐层进行返回。

递归的两个条件

需要注意的是,递归必须满足以下两个条件:

  1. 存在递归结束条件。
  2. 每进行一次递归,都会逐渐逼近结束条件。

以上述的factor函数为例,其递归结束条件就是if语句中的n == 1,当n为1的时候递归就结束了,而每次递归调用factor函数时传入的参数都是n - 1,因此每进行一次递归n的值都会逐渐逼近1。如果不能满足这两个条件,就会出现无限递归,最终导致栈溢出(Stack Overflow)。

说明一下: 函数调用时会在函数调用栈中记录每一层函数调用的信息,但函数调用栈的空间不是无限大的,如果函数调用层数太多,就会超出栈的最大范围,进而导致栈溢出。

递归的优缺点

递归的优点:

  • 递归类似于“数学归纳法”,明确初始条件,和递推公式,就可以解决一系列的问题。
  • 递归代码往往代码量非常少。

递归的缺点:

  • 递归代码往往难以理解,很容易超出掌控范围。
  • 递归代码容易出现栈溢出的情况。
  • 递归代码往往可以转换成等价的循环代码,并且通常来说循环版本的代码执行效率要略高于递归版本,因为函数的调用也是需要开销的。

默认参数与变长参数

默认参数

可以给函数的形参指定默认值,在调用函数时可以不必给带有默认值的形参传参,此时该形参将会使用我们指定的默认值。

例如,下面调用Add函数时如果不传入第二个参数,则默认返回第一个参数与1的和,如果调用Add函数时传入了第二个参数,则返回这两个参数的和。

def Add(data, val=1):
    return data + val


print(Add(10))     # 11
print(Add(10, 2))  # 12

注意: 在定义函数时,带有默认值的参数需要放到没有默认值的参数后面。

变长参数

如果想让函数接收任意个数的参数,可以在函数定义的形参名称前面添加*,这时函数将接收一个参数元组,并且我们可以以形参名[下标]的方式相应地访问传入的各个实参。比如:

def Func(*arg):
    n = len(arg)
    for i in range(n):
        print(arg[i])


Func(1)
Func(1, 2, 3)

说明一下: 元组是Python中的一个数据类型,本文先不做介绍。

变量作用域

变量的作用域

每一个变量都有自己的作用域:

  • 定义在函数内部的变量,其作用域仅在该函数内部,称为“局部变量”。
  • 定义在函数外部的变量,其作用域是全局的,称为“全局变量”。

注意事项:

  • 变量只能在自己所在的函数内部生效。
  • 在不同的作用域中,允许存在同名的变量。

函数中操作全局变量

需要注意的是,如果在函数内部尝试访问的变量在局部不存在,就会尝试去全局域中查找。比如:

x = 10

def Func():
    print(f'x = {x}')

Func()  # x = 10

但如果想要在函数内部修改全局变量的值,就需要使用global关键字进行声明。比如:

x = 10

def Func():
    global x  # 声明
    x = 20
    print(f'函数内部: x = {x}')  # x = 20

Func()
print(f'函数外部: x = {x}')  # x = 20

如果在函数内部修改全局变量时没有用global关键字进行声明,那么此时Python解释器会认为你是想在函数内部创建一个同名的局部变量,此时你的修改操作就不会影响到对应的全局变量。比如:

x = 10

def Func():
    # global x
    x = 20
    print(f'函数内部: x = {x}')  # x = 20

Func()
print(f'函数外部: x = {x}')  # x = 10

if、while、for中的变量

Python中的if、while、for等语句块不会影响变量的作用域,因此在这些语句块中定义的变量,也能在外面正常使用。比如:

for i in range(10):
    print(f'函数内部: i = {i}')

print(f'函数外部: i = {i}')  # i = 9

你可能感兴趣的:(Python,python,开发语言)