【python基础(七)】函数【一】:函数定义、函数调用、函数传参、返回值、作用域

总体来说,函数的两个主要目的是:降低编程难度和实现代码复用。 函数是一种功能抽象,复用它可以将一个复杂的大问题分解成一系列简单 的小问题,同时,小问题还可以继续划分成更小的问题,是一种分而治之 的思想应用。当每个小问题都细化到足够简单时,为每个小问题编写程 序,并通过函数封装,由小问题的解决到整个大问题的解决。这就是一种 自顶向下的程序设计思想。

一. 函数定义

def 函数名(参数1,参数2,...): 
	函数体
return 返回值列表

函数定义

  • def:关键字,标志着函数的开始;
  • 函数名: 函数唯一的标识,命名方式遵循变量的命名规则;
  • 参数:参数列表中的参数是形式参数,是调用该函数时传递给它的值,可以是0个,也可以是一个或多个。当传递多个参数时,各参数由逗号分隔。没有参数也需要保留括号。形参只在函数体中有效。
  • 函数体: 冒号:用于标记函数体的开始。函数每次被调用时执行的代码,由一行或多行代码组成。
  • return:
    • 标志函数的结束,将返回值赋给函数的调用者。
    • 若是没有返回值,则无须保留return语句,在函数体结束位置将控制权返回给调用者。

 

二. 函数调用

调用时,参数列表中给出实际要传入函数内部的参数,这类参数称为实际参数,即“实参”。实参可以是变量、常量、表达式、函数等。

在程序执行过程中,调用函数其实分成了4个步骤:

  1. 调用程序在调用处暂停执行。
  2. 在调用时将实参复制给函数的形参。
  3. 执行函数体语句。
  4. 函数结束时给出返回值,程序回到调用前暂停处继续执行。

在这里插入图片描述

  • 主程序先按顺序执行到c=fact(n)/(fact(m)∗fact(n-m)) 时,暂停,转到函数fact()。
  • 将实参n复制后传递给形参a。
  • 执行函数fact()中的语句。
  • 函数执行结束时,得到返回值f,回到主程序c=fact(n)/ (fact(m)∗fact(n-m)),得到了fact(n)的值。
  • 以同样的方式再次暂停,调用函数求得fact(m)、fact(n-m)的值。
  • 回到主程序c=fact(n)/(fact(m)∗fact(n-m)),继续往下执 行print©。

 

三. 向函数传参

1. 位置传参

def fmax(a, b):
    return max(a, b)

fmax(1, 2)  # 1赋给a,2赋给b

 

2. 关键字传参

关键字实参是传递给函数的名称值对。关键字实参让你无须考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。

def describe_pet(animal_type, pet_name):
    """显示宠物的信息。"""
    print(f"\nI have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")

if __name__ == '__main__':
# 关键字实参的顺序无关紧要,因为Python知道**各个值该赋给哪个形参**。下面两个函数调用是等效的:
    describe_pet(animal_type='hamster', pet_name='harry')
    describe_pet(pet_name='harry', animal_type='hamster')

 

3. 参数默认值

编写函数时,可给每个形参指定默认值。

如果你发现调用describe_pet()时,描述的大多是小狗,就可将形参animal_type的默认值设置为’dog’。这样,调用describe_pet()来描述小狗时,就可不提供这种信息:

def describe_pet(pet_name, animal_type='dog'):
    """显示宠物的信息。"""
    print(f"\nI have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")

if __name__ == '__main__':
    describe_pet(pet_name='willie')

# I have a dog.
# My dog's name is Willie.


# 虽然给animal_type指定了默认值,但py依然将这个参数视为位置参数。所以如果函数调用中只包含宠物的名字,这个实参将关联到函数定义的形参。所以这就是需要将pet_name放在形参列表开头的原因。
describe_pet('willie')

 

4. 包裹传递

  • 又称不定参数传递,适用于不知道函数要接收多少个参数的情况。
  • 传递的参数需要在位置传递和默认值传递之后。包括:*args(接收元组),**kwargs(关键字的map)
def fmax(*args):
    return max(args)
fmax(1, 2, 3)  # args被解释为一个元组,返回其中最大的数3


def fmax(**kwargs):
    return max(kwargs.values())
fmax(a=1, b=2, c=3)  # 返回3

 

5. 解包裹传递

解包裹传递是让容器里面的元素与多个参数一一对应。

  • 使用*解包序列(元组、列表均可),使其元素称为独立的参数位置参数:
  • 使用**解包字典,使其元素称为独立的关键字参数。

如下前两种比较常用,第三种不常用:

def fmax(a,b,c,d):
    return max(a,b,c,d)
numbers=[1,3,2,4]
fmax(*numbers) # numbers列表解包分别传递给a,b,c,d


def fmax(a,b,c,d):
    return max(a,b,c,d)
values={'a':1,'b':3,'c':2,'d':4}
fmax(**values) # 相当于fmax(a=1,b=3,c=2,d=4)


def func(*args):
    print(args)
args = (1,3,4)
func(*args)  #(1, 3, 4)      #解包,所以元组有三个元素
func(args)   #((1, 3, 4),)   #没有解包,所以元组只有一个元素

 

6. 混合传递

# 1. 混合使用位置传递、默认值传递和可变位置参数
def fmax(a, b=10, *args):
    numbers = (a, b) + args
    return max(numbers)
fmax(3)  # a=3,b使用默认值10,没有其他参数,返回10
fmax(3, 4, 6, 8, 1)  # a=3,b=4,args=(6,8,1),返回8


# 2. 混合使用位置传递、默认值传递、可变位置参数和可变关键字参数
def fmax(a, b=10, *args, **kwargs):
    # 接收map
    numbers = (a, b) + args + tuple(kwargs.values())
    return max(numbers)
fmax(3, 4, 2, 9, x=5, y=7)  # a=3,b=4,args=(2,9),kwargs={'x':5,'y':7},返回9
fmax(3, x=11, y=6)  # a=3,b使用默认值10,没有位置参数,kwargs={'x':11,'y':6},返回11

如果要让函数接受不同类型的实参,必须将接纳任意数量实参的形参放在最后

def make_pizza(size, *toppings):
    """概述要制作的比萨。"""
    print(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
        print(f"- {topping}")


if __name__ == '__main__':
    make_pizza(16, 'pepperoni')
    make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

注意:你经常会看到通用形参名*args,它也收集任意数量的位置实参。
 

 

四. 返回值

  • return是可选项,它的作用是结束并退出当前函数,将程序返回到函数被调用时的位置继续执行,同时将函数中的数据返回给主程序。

  • return语句可以同时返回多个结果给函数调用处的变量。当存在多个返回值时,会形成一个元组。

def mult(n):
    s = 0
    m = 1
    for i in range(1, n + 1):
        s += i
        m *= i
    return s, m


sum, mul = mult(5)
print('累加之和:{},阶乘之积:{}'.format(sum, mul))
t = mult(6)
print(type(t))

# 累加之和:15,阶乘之积:120
# <class 'tuple'>

返回值有两个,可以用两个变量接收。

 

五. 变量作用域

Python中的变量不是在哪个位置都可以访问的,具体的访问权限取决于定义变量的位置。变量所处的有效范围称为变量的作用域。

根据变量作用域的不同,可以将变量分为两类:全局变量和局部变量。

  • 全局变量是指在函数之外定义的变量,一般没有缩进,在程序执行的全过程有效。
  • 局部变量是指在函数内部定义的变量,
    • 仅在函数内部有效,一旦退出函数,变量就不再有效。
    • 想要在函数中使用全局变量,一般会使用global声明。
简单数据类型变量在主程序和函数体中重名.py
n = 1
def fun(a, b):
    n = a * b
    return a + b

s = fun(10, 12)
print(s, n)

简单数据类型在函数体中使用global声明.py
n = 1
def fun(a, b):
    global n
    n = a * b
    return a + b
s = fun(10, 12)
print(s, n)

组合数据类型在主程序中创建,在函数体中使用.py
ls = []
def fun(a, b):
    ls.append(a * b)
    return a + b
s = fun(10, 12)
print(s, ls)

组合数据类型在主程序中创建,在函数体中再创建并使用.py
ls = []
def fun(a, b):
    ls = []
    ls.append(a * b)
    return a + b
s = fun(10, 12)
# ls返回为空
print(s, ls)

由此,可以总结一下Python函数对变量的作用要遵守的原则:

  1. 简单数据类型变量在使用global保留字声明后,作为全局变量使用,函数退出后,该变量仍被保留,且数值被函数改变。
  2. 如果函数内部真实地创建了组合数据类型变量,无论是否与全局变量同名,函数仅对内部的局部变量进行操作,函数退出后局部变量被释放,而全局变量的值不受函数影响。

 

 

参考:《Python编程:从入门到实战(第二版)》

Python中,要在函数内部使用全局变量,可以使用global关键字将变量声明为全局变量。首先,在函数外部给变量赋初值,然后在函数内部使用global关键字声明该变量为全局变量。例如,如果有一个全局变量a,在函数内部需要使用它,可以在函数内部使用"global a"来声明a为全局变量,然后就可以使用a了。需要注意的是,不能在global语句中同时给变量赋值,只能在global语句之前先给变量赋值。比如,要将a设置为5,应该先使用global a声明a为全局变量,然后再将a设置为5,即global a a=5。这样,函数内部就可以使用全局变量a了。 请参考以了解更多关于在Python函数中调用全局变量的方法和注意事项。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Python如何在函数内部使用全局变量](https://blog.csdn.net/hnjzsyjyj/article/details/121433141)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [python函数里引用全局变量](https://blog.csdn.net/edward_zcl/article/details/116163319)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roman_日积跬步-终至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值