Python函数介绍(二)

1. 实参的类型

  • 实参可以传递任意类型的对象;
def fn(a):
    print('a = ', a)

print('传递整数参数: ', end='')
b = 123
fn(b)
print('传递字符串参数: ', end='')
b = 'hello'
fn(b)

运行结果:

在这里插入图片描述

  • 调用函数的时候,解析器不会检查实参的类型;
def fn(a, b):
    print(f'{a} + {b} = {a + b}')

# 传递了一个整数和字符串参数
fn(1, '2')
# 错误信息:
TypeError: unsupported operand type(s) for +: 'int' and 'str'

运行结果:
在这里插入图片描述

解析器不检查实参类型,编写代码时不会发出警告。

  • 在函数中重新给形参赋值,不会影响传递的变量;
def fn(a):
    # 在函数中给形参赋值
    a = 10
    print('a = ', a, ', id(a) = ', id(a))

c = 1
fn(c)
print('c = ', c, ', id(c) = ', id(c))

运行结果:
在这里插入图片描述
使用 = 赋值运算符会改变变量指向的对象,上述代码中函数中的变量a和c已经指向不同的对象。

  • 如果现在的形参执行的是可变对象,当我们通过形参修改对象时,会影响到所有指向该变量的对象
def fn(a):
    # 形参a传递列表,修改列表中的某个元素
    a[0] = 10
    print('a = ', a, ', id(a) = ', id(a))

c = [1, 2, 3]
fn(c)
print('c = ', c, ', id(c) = ', id(c))

运行结果:
在这里插入图片描述
对于上述结果,笔者的理解是参数传递时实参将会赋值给对应的形参,此时a和c指向同一个对象即列表[1,2,3],而使用下标修改列表元素,不会改变变量指向的对象,列表作为可变对象,列表元素修改后所有指向它的变量都会受影响。
如果不希望函数中改变a会影响c,就可以之前课程中提及的copy方法。

# fn(c)
fn(c.copy())

运行结果:

在这里插入图片描述

2. 不定长参数

2.1 带*参数的使用

  • 在定义函数的时候,可以在形参之前加上*号,这个形参可以获取到所有的实参,它会将获取到的实参放到一个元祖当中;
def fn(*a):
    print('a = ', a, type(a))

print('不传递实参:', end='')
fn()
print('传递任意数量实参:', end='')
fn('hello', 1, 2.0, True, [1, 2, 3])

运行结果:

在这里插入图片描述

*args 会接受所有位置实参,并且会统一保存到一个元祖当中。

小练习:求任意数量的参数之和。

def mysum(*args):
    # 定义变量保存结果
    a = 0
    # 遍历元祖,将元祖中的数进行相加
    for i in args:
        a += i
    print('result = ', a)
mysum(1, 2, 3, 4)

运行结果:
在这里插入图片描述

  • 带*号的形参只能有一个;
  • 不定长参数不一定非要写最后,但是带*参数后面的参数,都必须以关键字参数的方式进行传递;
def fn1(a, b, *c):
    print('a = ', a)
    print('b = ', b)
    print('c = ', c)
print('带*形参放在最后:')
fn1(1, 2, 3, 4, 5)

在这里插入图片描述

def fn2(a, *b, c):
    print('a = ', a)
    print('b = ', b)
    print('c = ', c)
print('带*形参放在中间,后续不用关键字传参:')
fn2(1, 2, 3, 4, 5)

运行结果:

在这里插入图片描述

def fn2(a, *b, c):
    print('a = ', a)
    print('b = ', b)
    print('c = ', c)
print('带*形参放在中间,后续为关键字传参:')
fn2(1, 2, 3, 4, c = 5)

运行结果:

在这里插入图片描述

  • 带*参数没有写在最后,若之后的参数没有使用关键字传参且有默认值的情况下,也不会报错,那么该参数将使用默认值,传递的参数去除原本的位置参数外,都将打包给*参数。
def fn2(a, *b, c=5):
    print('a = ', a)
    print('b = ', b)
    print('c = ', c)
print('带*形参放在中间,后续形参有默认值:')
fn2(1, 2, 3, 4)

运行结果:

在这里插入图片描述

从上述代码运行的结果看:* 形参只能接收位置参数。

2.2 带**参数的使用

  • ** 形参可以接收其它关键字参数,它会将这些参数统一保存到一个字典当中。
    在该字典中,key就是参数的名字,字典的value就是参数值。

  • ** 形参只能有一个,并且只能写在最后面.

def fn3(a, b, **c):
    print('a = ', a)
    print('b = ', b)
    print('c = ', c)
print('带**形参的使用:')
fn3(d = 3, e = 4, a = 1, b = 2)

运行结果:

在这里插入图片描述

a和b使用关键字传参时可以不用按照其原本的位置,剩余参数都必须以关键字传参的方式给c,并且被转换为字典使用。
从上述代码运行的结果看:** 形参处理关键字参数。

3. 函数的返回值

  • 返回值就是函数执行以后返回的结果,可以通过return来指定函数的返回值;
  • 可以直接使用函数的返回值,也可以通过一个变量来接收函数的返回值;
def fn1():
    return 123
def fn2():
    return 'hello'
def fn3():
    return [1, 2, 3, 4]
def fn4():
    return {'name': 'John', 'age': 10}
# 通过变量接收函数返回值
r = fn1()
print('返回整数:', r)
r = fn2()
print('返回字符串:', r)
r = fn3()
print('返回列表:', r)
r = fn4()
print('返回字典:', r)

运行结果:

在这里插入图片描述

  • return 可以接任何对象
    函数没有写return,或者只写了return,那么相当于return None
def fn1():
    print('This is fn1', end=' ')
    return None
def fn2():
    print('This is fn2', end=' ')
def fn3():
    print('This is fn3', end=' ')
    return
r = fn1()
print('返回值:', r)
r = fn2()
print('返回值:', r)
r = fn3()
print('返回值:', r)

运行结果:

在这里插入图片描述

  • 在函数中,return 后面的代码不会执行,return一旦执行,函数自动结束。
def fn3():
    for i in range(5):
        if i == 3:
            break
        print('i = ', i)
    print('循环执行完毕')
fn3()

上述代码的执行结果如下:

在这里插入图片描述

如果在语句print('循环执行完毕') 前加上return,执行结果如下:

在这里插入图片描述

4. 函数的作用域

作用域就是变量生效的区域。

  • 全局作用域
    全局作用域在程序执行时创建,在程序执行结束时销毁。
    所有函数以外的区域都是全局作用域。
    在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置进行访问。
  • 函数作用域
    函数作用域在函数调用时创建,在调用结束时销毁。
    函数每调用⼀次就会产生⼀个新的函数作用域。
    在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问。
b = 20
def fn():
    a = 10
    print('函数内部, a = ', a)
    print('函数内部,b = ', b)
fn()
print('函数外部,b = ', b)
print('函数外部, a = ', a)

运行结果:
在这里插入图片描述

  • 如果希望在函数内部修改全局变量的指向,则需要使用global关键字,声明变量。
a = 10
def fn():
    a = 20
    print('函数内部, a = ', a)
fn()
print('函数外部, a = ', a)

运行结果:

在这里插入图片描述

a = 10
def fn():
    global a # 使用global关键字声明a
    a = 20
    print('函数内部, a = ', a)

fn()
print('函数外部, a = ', a)

运行结果:

在这里插入图片描述

变量a被global声明后,表示全局变量。函数内部对其重新赋值后,函数外部访问该变量时已经是修改后的值。

5. 递归函数

递归是解决问题的⼀种方式,它和循环很像。
递归式函数就是在函数中自己调用自己。
递归的整体思想是:将⼀个大问题分解为⼀个个的小问题,直到问题无法分解时,再去解决问题。
递归式函数有2个条件:

  1. 基线条件
    问题可以被分解为最小问题,当满足基线条件时,递归就不再执行。
  2. 递归条件
    可以将问题继续分解的条件。

代码样例:

# 创建一个函数,用递归的方式
def fn(n):
    # 基线条件
    if n == 1:
        return 1
    # 递归条件
    return n * fn(n-1)
n = 10
r = fn(n)
print(f'{n}的阶乘为:', r)

运行结果:
在这里插入图片描述

# 创建一个函数,为任意数字做任意幂运算
def fn1(n, i):
    # 基线条件
    if i == 1:
        return n
    # 递归条件
    return n * fn1(n, i-1)
n = 5
i = 6
r = fn1(n, i)
print(f'{n}{i}次幂为:', r)

运行结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值