函数那些事儿

本文深入讲解Python函数的各种参数类型,包括位置参数、默认参数、可变参数、关键字参数及命名关键字参数,探讨参数传递机制,详解函数定义与调用过程,并提供丰富示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天让我们聊聊函数的那些事儿~

  • Tip 1:函数的定义:
    Python定义一个函数使用def保留字,语法形式如下:
def <函数名>(<参数列表>):
	<函数体>
	return <返回值列表>
  • tip 2:形参和实参
    形式参数(形参):在函数创建和定义过程中使用的参数。
    实际参数(实参):在函数被调用的过程中传递进来的参数。
    形参只是代表一个位置,一个变量名,没有具体的值。
    实参是一个具体的值,是赋值到变量名中的值。
    实参默认按位置顺序依次传递给形参,若参数个数不对,报错。
演示:
>>> def func(a,b):
	print(a+b)
#这里的a,b就是形参
>>> func(1,2)  #这里的1,2就是实参
3

一、函数的参数传递

Python传入参数的方法有:位置参数、默认参数、可变参数、关键字参数和命名关键字参数、以及各种参数调用的组合

1.位置参数()

普通的参数叫做位置参数,调用时需要按照位置顺序传递参数值。
实参默认按位置顺序依次传递给形参,若参数个数不对,报错。
位置参数是最简单的传入参数的方式,在其它的语言中也常常被使用。

演示一:

>>> def func(a,b):
	print(a)
	print(b)
	
>>> func(99,100)
99
100
>>> func(100,99)
100
99
#传入的实参99和100,是按照a和b的位置顺序来匹配赋值的

>>> func(99)
Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    func(99)
TypeError: func() missing 1 required positional argument: 'b'
#参数的顺序和个数要和函数定义中一致,有两个形参就要有两个实参 

演示二:

>>> def power(x, n):
	s=1
	while(n > 0):
		n -= 1
		s *= x
	return s

>>> power(2,3)
8
#函数power(x,n)中有两个参数—— x和n,这两个参数都是位置参数,
调用函数的时候,传入的两个实参2和3,按照顺序,依次赋值给x和n。

2.可选参数(默认值参数)

作用:最大的好处就是降低调用函数的难度。

1.在定义函数时,如果有些参数存在默认值,即部分参数不一定需要调用程序输入,可以在定义函数时直接为这些参数指定默认值,则使用更少的参数调用。
2.当函数被调用时,如果没有传入对应的参数值,则使用函数定义时的默认值替代。

>>> def funcA(a,b=2):  #b就是默认参数,默认值为2
	print(a)
	print(b)
	
>>> funcA(3)  #对应第二条。因为按顺序调用赋值,则a=3,b没传入值就输出默认值2。 
3
2
>>> funcA(3,4) #b有传入值时输出传入值
3
4

Tips:

  • 必选参数(位置参数)在前,可选参数(默认参数)在后。
  • 当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。
  • 默认参数一定要指向不变对象!指向不变对象!指向不变对象!
    (注意:python中的字符串,数字,元组都可以看做对象。)

(划重点)假如默认参数是可变对象(如列表,字典或大多数类的实例)是会有副作用的,或者说一个函数参数的默认值,仅仅在该函数定义的时候,被赋值一次.如此,只有当函数第一次被定义的时候,才将参数的默认值初始化到它的默认值(如一个空的列表)。*
>>> def f(a,L=[]):  #L是一个空列表
	L.append(a)
	return L

#函数参数不传递时默认值总是指向固定的内存空间,就是第一次计算的空间。
>>> print(f(1))
[1]
>>> print(f(2))
[1, 2]
>>> print(f(3))
[1, 2, 3]

如果不希望在后续调用之间共享默认值,则可以编写如下函数:

>>> def f(a,L=None):
	if L is None:
		L= []
	L.append(a)
	return L

>>> print(f(1))
[1]
>>> print(f(2))
[2]
>>> print(f(3))
[3]

3.可变参数(可变数量参数)

定义:可变参数就是允许在调用参数的时候传入多个(≥0个)参数(类似于列表、字典)
作用:就是可以一次给函数传很多的参数
特征:*args 、**kw

  • 带有星号*的可变参数只能出现在参数列表的后面。调用时,这些参数被当作元组类型传递到函数中。
  • 在函数定义时,也可以通过在参数前增加带双星号(**)的参数,向函数传递可变数量的参数。带有双星号的可变参数只能出现在参数列表的最后。调用时,**后的那些参数被当作字典类型传递到函数中。(*c,**d)
>>> def func(*args): #这种定义会把传递的参数包成元组
        print(args,type(args))

>>>func(10,20)
#结果:
(10, 20) <class 'tuple'>

#举一个和上述过程相反的例子:
>>>def func(a,b):
       print('a=%d, b=%d' % (a,b) )

>>>a = (10, 20)
>>>func(*a) #在调用函数使用`*`则会把元组解包成单个变量按顺序传入函数
#结果:
a=10, b=20
总结:*号在定义函数参数时,传入函数的参数会转换成元组,如果 *号在调用时则会把元组解包成单个元素。

另一种定义:

>>>def func(**kw):  #使用**定义参数会把传入参数包装成字典dict
       print(kw, type(kw) ) 
      
>>>func(a=10,b=20)  #这种函数在使用时必须指定参数值,使用key=value这种形式 
#结果:
{'b': 20, 'a': 10} <class 'dict'>

#相反的例子:
>>>def func(a,b):
       print('a=%d, b=%d' % (a,b) )

>>>d = {'a':10, 'b':20 }
>>>func(**d) #在调用时使用**会把字典解包成变量传入函数。
a=10, b=20
总结:**号在定义函数参数时,传入函数的参数会转换成字典,如果 **号在调用时则会把字典解包成单个元素。
>>> def c(*nums):
	sum = 0
	for n in nums:
		sum += n
	return sum

>>> c(1,2,3)
6
>>> my = [1,2,3]
>>> c(*my)
6

4.关键字参数

关键字参数就是在调用函数,传入实参时指定形参的变量名。
Tip:

  • 关键字(keyword)传递是根据每个参数的名字传递参数。
  • 关键字不用遵守位置的对应关系。由于调用函数时指定了参数名称,所以参数之间的顺序可以任意调整。
  • 关键字传递可以和位置传递混用。但位置参数要在关键字参数之前。
  • 关键字参数的作用:扩展函数的功能
  • 特征:**kw。表示它接收包含所有关键字参数的字典,且放在最后。
>>> def hello(name,age = 11,gender = 'F'):
 #age = 11,gender = 'F'就是关键字参数
	print('User Info:')
	print('name is %s' % name)
	print('age is %d' %age)
	print('gender is %c'%gender)

>>> hello('Jim',age = 12) 
User Info:
name is Jim
age is 12
gender is F
>>> hello('Jim', age=11, gender='M')
User Info:
name is Jim
age is 11
gender is M
>>> hello('Jim',gender='M',age = 11)
User Info:
name is Jim
age is 11
gender is M

>>> hello(age = 11,'Jim')  #位置参数要出现在关键字参数之前
SyntaxError: positional argument follows keyword argument

可变参数允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
而关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。在调用函数时,可以只传入必选参数。

>>> def person(name,age,**kw):
	    print('name:', name, 'age:', age, 'other:', kw)
#函数person除了必选参数name和age外,还接受关键字参数kw。

#在调用该函数时,可以只传入必选参数:
>>> person('Michael', 30)
name: Michael age: 30 other: {}

#也可以传入任意个数的关键字参数:
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

#定义一个字典数据
>>>dictArray = {'city': 'Beijing', 'job': 'Engineer'}
#调用函数
>>>person('Jack', 24, **dictArray )
#输出结果
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
#解释:**dictArray表示把dictArray这个dict的所有key-value用关键字参数传入
到函数的**kw参数,kw将获得一个dict。注意kw获得的dict是dictArray的一份拷贝,
对kw的改动不会影响到函数外的dictArray。

5.命名关键字参数(强制命名参数keyword-only)

  • 和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数。如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了。
  • 在带星号的参数后面申明参数会导致强制命名参数(Keyword-only)。调用时必须显式使用命名参数传递值,因为按位置传递的参数默认收集为一个元组,传递给前面带星号的可变参数。
  • 如果不需要带星的可变参数,只想使用强制命名参数,可以简单地使用一个星号。例如:def my_func( *, a, b, c)
>>> def f(*c,a,b):
	return a+b
>>> f(a=3,b=5)
8

>>> def f(*,a,b):
	return a+b
>>> f(a=3,b=5)
8

>>> def f(*,a,b,rate=0.3):
	return (a+b)*rate
>>> f(a=3,b=5)
2.4
>>> f(a=3,b=5,rate = 0.5)
4.0

例二

#这里星号分割符后面的city、job是命名关键字参数
>>> def person_info(name, age, *, city, job):
	    print(name, age, city, job)

>>> person_info("Alex", 17, city = "Beijing", job = "Engineer")
Alex 17 Beijing Engineer    #看来这里不再被自动组装为字典
#函数定义中有了一个可变参数,后面跟着的命名关键字参数就不需要特殊分隔符`*`了。
#args是变长参数,而city和job是命名关键字参数 
>>>def person_info(name, age, *args, city, job): 
       print(name, age, args, city) 

>>>person_info("Liqiang", 43, "balabala", city = "Wuhan", job = "Coder") 
Liqiang 43 balabala Wuhan Coder

参考文献:
文献1
文献2

函数与过程

  • 函数:有返回值
  • 过程:无返回值
  • Python中只有函数,没有过程。如果没有return语句,默认返回None。
  • 变量的返回值:
    return语句用来退出函数并将程序返回到函数被调用的位置继续执行。return语句同时可以将0个、1个或多个函数运算完的结果返回给函数被调用处的变量。
>>> def func(a, b):
	return a*b

>>> s = func("knock~",2)
>>> print(s)
knock~knock~

函数可以没有return,此时函数并不返回值。函数也可以用return
返回多个值,多个值以元组类型保存

>>> def func(a, b):
	return b,a

>>> s = func("knock~",2)

>>> print(s,type(s))
(2, 'knock~') <class 'tuple'>

lambda表达式

lambda表达式就是一种简单的函数
形如 f = lambda 参数1,参数2: 返回的计算值

>>>add = lambda x,y: x+y
>>>print(add(1,2))

#结果:
3

列表.sort()与全局sorted()比较

  • sort(): python list的内置方法
    sort(key=None,reverse=False) 就地改变列表; 但其返回值为None
    reverse:True反序;False 正序
  • sorted(): python内置的全局方法
    sorted(iterable,key=None,reverse=False),返回新的列表,对所有可迭代的对象
    均有效
>>> x= [3,7,5]
>
>>> print(x.sort())
None

>>> print(sorted(x))
[3, 5, 7]

reverse() 和reversed()的区别

  • reverse():列表list的内置方法
    用于列表中数据的反转
>>> l = [1,2,3,4]
>>> l.reverse()
>>> print(l)
[4, 3, 2, 1]

其实,list.reverse()这一步操作的返回值是None,结果需要通过打印被作用的列表后才能知道。

  • reversed():Python 自带的一个方法,或说是一个类。

reversed(sequence) - > 反转迭代器的序列值
返回反向迭代器

即经过reversed()的作用后,返回的是一个把序列值经过反转后的迭代器
所以需要通过遍历,或者list,或者next()等方法,获取作用后的值。

#列表的反转
>>> bb = [1,2,4,6]
>>> reversed(bb)
<list_reverseiterator object at 0x000002CE2F8787B8>
>>> list(reversed(bb))
[6, 4, 2, 1]

#元组的反转
>>> aa = (1,2,3)
>>> reversed(aa)
<reversed object at 0x000002CE2F846D68>
>>> tuple(reversed(aa))
(3, 2, 1)

函数变量的作用域

  • 局部变量
  • 全局变量
  • global:若确需在函数中直接修改全局变量的值,可以使用global关键字。

Tip:global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也可以不使用global关键字。

>>> a = 5 #这个a是全局变量
>>> def f4(b,c):
	a = a+b*c #这个a是局部变量
	return a  #这个a也是局部变量
>>>print(a)
5  #返回全局变量a的值

>>> f4(2,3)  #因为经过函数作用之后的a的值改变了,不等于5,则报错
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    f4(2,3)
  File "<pyshell#12>", line 2, in f4
    a = a+b*c
UnboundLocalError: local variable 'a' referenced before assignment

#global 的力量
>>> def f5(b,c):
	global a
	a = a+b*c
	return a

>>> f5(2,3)
11
>>> print(a)
11
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值