[Python] 函数详解

🎶博客主页:程序喵正在路上 的博客主页
🦋欢迎关注🖱点赞👍收藏🌟留言🐾
🦄本文由 程序喵正在路上 原创,CSDN首发!
💖系列专栏:Python学习
🌠首发时间:2022年5月2日
✅如果觉得博主的文章还不错的话,希望小伙伴们三连支持一下哦

1. 函数的基本使用

1.1 函数的定义

函数是一段具有特定功能的、 可重用的语句组,用函数名来表示并通过函数名进行功能调用。函数也可以看作是段具有名字的子程序,可以在需要的地方调用执行。不需要再每个执行的地方重复编写这些语句。每次使用函数可以提供不同的参数作为输入,以实现对不同数据的处理;函数执行后,还可以反馈相应的处理结果。

函数能够完成特定功能,与黑盒类似,对函数的使用不需要了解函数内部实现原理,只要了解函数的输入输出方式即可。严格地说,函数是一种功能抽象。

有些函数是用户自己编写的,称为自定义函数;Python 安装包也自带了一些函数和方法,包括 Python 内置的函数(如 abs()eval()Python 标准库中的函数(如 math 库中的 sqrt() 等。

使用函数主要有两个目的:降低编程难度和代码重用。函数是一种功能抽象,利用它可以将-一个复杂的大问题分解成一系列简单的小问题,然后将小问题继续划分成更小的问题,当问题细化到足够简单时,就可以分而治之,为每个小问题编写程序,并通过函数封装,当各个小问题都解决了,大问题也就迎刃而解。这是一种自顶向下的程序设计思想。函数可以在一个程序中的多个位置使用,也可以用于多个程序,当需要修改代码时,只需要在函数中修改一次,所有调用位置的功能都更新了,这种代码重用降低了代码行数和代码维护难度。

Python 使用 def 保留字定义一个函数,语法形式如下:

def <函数名>(<参数列表>) :
  <函数体>
  return <返回值列表>

函数名可以是任何有效的 Python 标识符;参数列表是调用该函数时传递给它的值,可以有零个、一个或多个,当传递多个参数时各参数由逗号分隔,当没有参数时也要保留圆括号。函数定义中参数列表里面的参数是形式参数,简称为 “形参”。函数体是函数每次被调用时执行的代码,由一行或多行语句组成。当需要返回值时,使用保留字 return 和返回值列表,否则函数可以没有 return 语句,在函数体结束位置将控制权返回给调用者。

函数调用和执行的一般形式如下:
<函数名>(<参数列表>)

此时,参数列表中给出了要传入函数内部的参数,这类参数称为实际参数,简称 “实参”。

例如,我们编写一个输出生日歌的程序,歌词为
Happy birthday to you!
Happy birthday to you!
Happy birthday, dear <名字>
Happy birthday to you!

最简单的实现方法是重复使用 print() 语句,对 LiHua 的生日歌输出如下:

print("Happy birthday to you!")
print("Happy birthday to you!")
print("Happy birthday, dear Mike!")
print("Happy birthday to you!")

其中,第 1、2、4 行代码相同,假如需要将 birthday 改为 new year,则每处都要修改。为了避免这种情况,可以用函数进行封装。上述代码中除第 3 行有微小不同外其余代码完全一致, 这会带来重复代码,为了能够复用语句,考虑将代码修改为:

def happy():
    print("Happy birthday to you!")

def happyB(name):
    happy()
    happy()
    print("Happy birthday, dear {}!".format(name))
    happy()

happyB("Mike")
print()
happyB("LiHua")

程序的执行结果如下:

Happy birthday to you!
Happy birthday to you!
Happy birthday, dear Mike!
Happy birthday to you!

Happy birthday to you!
Happy birthday to you!
Happy birthday, dear LiHua!
Happy birthday to you!

改进后的代码中的第 4 行定义了一个函数 happyB(),括号中的 name 是形参,用来指代要输入函数的实际变量,并参与完成函数内部功能。第 10 和第 12 行调用两次 happyB() 函数,输入的 “Mike” 和 “LiHua” 是实参,替换 name,用于函数执行。

1.2 函数的调用过程

程序调用一个函数需要执行以下 4 个步骤:
(1) 调用程序在调用处暂停执行。
(2) 在调用时将实参复制给函数的形参。
(3) 执行函数体语句。
(4) 函数调用结束给出返回值,程序回到调用前的暂停处继续执行。

对前面实例的生日歌程序跟踪分析。第 1 到第 9 行是函数定义,函数只有在被调用时才执行,因此,前 9 行代码不直接执行。程序最先执行的语句是第 10 行的 happyB(“LiHua”)。当 Python 执行到这行时,由于调用了 happyB() 函数,当前执行暂停,程序用实参 “Mike” 替换 happyB(name) 中的形参 name,形参被赋值为实参的值,类似执行了如下语句:

name = “Mike”

然后,使用实参代替形参执行函数体内容。当函数执行完毕后,重新回到第 10 行,继续执行余下语句。函数第 10 行的执行过程如下图所示,这里函数 happyB() 的变量 name 被自动替换为 Mike

在这里插入图片描述

当程序执行 happyB() 函数体时,第一条执行语句是 happy() 函数,这也是一个函数调用。因此,Python 暂停执行 happyB() 函数,将控制传递给被调用的函数 happy()happy() 函数体包含了一个简单的 print 语句,该语句执行后函数体结束,程序重新返回调用 happy() 函数的位置。下图给出了 happyB() 函数调用和返回的执行过程。

在这里插入图片描述

程序执行完 happyB() 函数体后,返回调用该函数的原始位置,继续执行,如下图所示。

在这里插入图片描述

1.3 函数式编程

函数式编程是一种编程范式,常见的编程范式还包括命令式编程和面向对象编程等。函数式编程的主要思想是把程序过程尽量写成一系列函数调用,通过函数进一步提高封装级别。函数式编程通过使用一系列函数能够使代码编写更简洁、更易于理解,是中小规模软件项目中最常用的编程方式。

1.4 lambda 函数

Python33 个保留字,其中一个是 lambda,该保留字用于定义一种特殊的函数——匿名函数,又称 lambda 函数。匿名函数并非没有名字,而是将函数名作为函数结果返回,语法格式如下:

<函数名> = lambda <参数列表>: <表达式>

lambda 函数与正常函数一样,等价于下面形式:

def <函数名>(<参数列表>) :
return <表达式>

简单地说,lambda 函数用于定义简单的、能够在一行内表示的函数,返回一个函数类型,实例如下:

f = lambda x, y: x + y
print(type(f))

a=f(10,12)
print(a)

程序执行结果如下:

<class ‘function’>
22

lambda 函数用于需要函数对象的场景。

2. 函数的参数传递

2.1 可选参数和可变数量参数

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

def dup(str, times=2):
    print(str * times)

dup("knock~")

dup("knock~", 4)

程序执行结果如下:

knock~ knock~
knock~ knock~ knock~ knock~

由于函数调用时需要按顺序输入参数,可选参数必须定义在非可选参数的后面,即 dup() 函数中带默认值的可选参数 times 必须定义在 str 这个参数后面。

在函数定义时,也可以设计可变数量参数,通过在参数前增加星号 (*) 实现。带有星号的可变参数只能出现在参数列表的最后。调用时,这些参数被当作元组类型传递到函数中,实例如下:

def vfunc(a,*b):
    print(type(b))	# 打印b的类型
    for n in b:
        a += n
        
    return a       # 返回a的值

print(vfunc(1,2,3,4,5))

程序执行结果如下:

<class ‘tuple’>
15

vfunc() 函数定义了可变参数 b,调用 vfunc() 函数时输入的 (2, 3, 4, 5) 被当作元组传递给 b,与 a 累加后输出。如果你还没有学习元组,这里可以将元组理解为一组元素。

2.2 参数的位置和名称传递

函数调用时,实参默认采用按照位置顺序的方式传递给函数,例如 dup("knock- ",4) 中第一个实参默认赋值给形参 str,第二个实参赋值给形参 times。这种按照位置传递参数的方法固然很好,但当参数很多时,这种调用参数的方式可读性较差。假设 func() 函数有 6 个参数,它的定义如下,其中参数分别表示两组三维坐标值。

 func(x1, y1, z1, x2, y2, z2):
  return

它的一个实际调用如下:
result = func(1, 2,3,4,5,6)

如果仅看实际调用而不看函数定义,很难理解这些输入参数的含义。在规模稍大的程序中,函数定义可能在函数库中,也可能与调用相距很远,带来的可读性较差。

为了解决上述问题,Python 提供了按照形参名称输入实参的方式,此时函数调用如下:

result = func(x2=4, y2=5,z2=6, x1=1, y1=2, z1=3)

由于调用函数时指定了参数名称,所以参数之间的顺序可以任意调整。

2.3 函数的返回值

return 语句用来退出函数并将程序返回到函数被调用的位置继续执行。reum 语句可以同时将 0 个、1 个或多个函数运舞后的结果返回给函数被调用处的变量,例如:

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

a = func("knock~ ", 2)
print(a)

程序执行结果如下:

knock~ knock~

函数可以没有 return,此时函数并不返回值,比如前面的生日歌程序。函数也可以用 return 返回多个值,多个值以元组类型保存。例如:

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

a = func("knock~ ", 2)
print(a, type(a))

程序执行结果如下:

(2, 'knock~ ') <class ‘tuple’>

2.4 函数对变量的作用

一个程序中的变量包括两类:全局变量和局部变量。全局变量指在函数之外定义的变量,一般没有缩进,在程序执行全过程有效。局部变量指在函数内部使用的变量,仅在函数内部有效,当函数退出时变量将不存在。例如:

n = 1           # n 是全局变量
def func(a,b):
    c = a * b
    return c
s = func("knock~ ",2)
print(c)

程序执行结果如下:

Traceback (most recent call last):
File “D:\pythonProject\venv\est.py”, line 6, in < module >
print(c)
NameError: name ‘c’ is not defined

这个例子说明,当函数执行完退出后,其内部变量将被释放。如果函数内部使用了全局变量呢?例如:

n = 1           # n 是全局变量

def func(a, b):
    n = b    # 这个n 是在函数内存中新生成的局部变量,不是全部变量
    return a * b

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

程序执行结果如下:

knock~ knock~ 1

函数 func() 内部使用了变量 n,并且将变量参数 b 赋值给变量 n,为何 n 值没有改变?因为函数 func() 有自己的内存空间,它将 n=b 语句理解为生成一个局部变量 n,并将参数 b 赋值给它,此时 func() 函数没有将 n 当作全局变量。所以,函数退出后,局部变量 n 被释放,全局变量 n 的值没有改变。

如果希望让 func() 函数将 n 当作全局变量,需要在变量 n 使用前显式声明该变量为全局变量,代码如下:

n = 1                    # n 是全局变量

def func(a, b):
    global n
    n = b               # 将局部变量 b 赋值给全局变量 n
    return a * b

s = func("knock~ ", 2)
print(s, n)             # 测试一下 n 值是否改变

程序执行结果如下:

knock~ knock~ 2

如果此时的全局变量不是整数 n,而是列表类型 ls,会怎么样呢?
试着理解如下代码:

ls = []            # ls 是全局列表变量

def func(a, b):
    ls.append(b)  # 将局部变量 b 增加到全局列表变量 ls 中
    return a * b

s = func("knock~ ", 2)
print(s, ls)      # 测试一下 n 值是否改变

程序执行结果如下:

knock~ knock~ [2]

请读者注意,奇迹产生了,与之前的整数变量 n 不同,全局列表变量在函数 func() 调用后竟然发生了改变 !

——这是为什么?灵异事件?
——Python 才刚刚开始展现它的魅力。

实际上,列表等组合数据类型由于操作多个数据,所以它们在使用中有创建和引用的分别。当列表变量被方括号([ ], 无论是否为空)赋值时,这个列表才被真实创建,否则只是对之前创建列表的一次引用。

上述代码 func() 函数的 ls.append(b) 语句执行时需要一个真实创建过的列表,此时 func() 函数专属的内存空间中没有已经创建过且名称为 ls 的列表,因此, func() 函数进一步去寻找全局内存空间,自动关联全局 Is 列表,并修改其内容。当 func() 函数退出后,全局 Is 列表中的内容被修改。简单地说,对于列表类型,函数可以直接使用全局列表而不需要采用 global 进行声明。

如果 func() 函数内部存在一一个真实创建过且名称为 Is 的列表,则 func() 函数将操作该列表而不会修改全局变量,例如:

ls = []                      # ls 是全局列表变量

def func(a, b):
    ls = []                 # 创建了名称为 ls 的局部列表变量
    ls.append(b)  			# 将局部变量 b 增加到局部列表变量 ls 中
    return a * b

s = func("knock~ ", 2)
print(s, ls)            	# 测试一下 n 值是否改变

程序执行结果如下:

knock~ knock~ []

总结一下,Python 函数对变量的作用遵守如下原则。
(1) 简单数据类型变量无论是否与全局变量重名,仅在函数内部创建和使用,函数退出后变量被释放,如有全局同名变量,其值不变。

(2) 简单数据类型变量在用 global 保留字声明后,作为全局变量使用,函数退出后该变量保留,且值被函数改变。

(3) 对于组合数据类型的全局变量,如果在函数内部没有被真实创建的同名变量,则函数内部可以直接使用并修改全局变量的值。

(4) 如果函数内部真实创建了组合数据类型变量,无论是否有同名全局变量,函数仅对局部变量进行操作,函数退出后局部变量被释放,全局变量值不变。

2.5 指针和引用

指针是保存内存地址的变量,一般出现在比较底层的程序设计语言中,如 C 语言。引用是某一变量的别名,用这个名字可以对变量进行操作,如 Python 列表类型的引用。两者的主要区别是,指针直接指向内存地址,说明对象已经生成,而引用只是别名,需要真实创建对象才能操作对象。由于列表类型在 Python 中十分常用,要格外注意该类型真实创建和引用的区别。

🧸这次的分享就到这里啦,继续加油哦^^
🍭有出错的地方欢迎在评论区指出来,共同进步,谢谢啦

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Python中,print函数用于将文本或变量输出到控制台。在Python 3.x版本中,print是一个函数,而在Python 2.x版本中,print是一个语句。因此,使用print函数的方式在这两个版本中略有不同。在Python 3.x中,使用print函数时,需要将要打印的内容放在括号中。例如,print("Hello World")将会打印出"Hello World"这个字符串。 在使用print函数时,还可以使用格式化字符串来打印变量的值。比如,print("Hello %s" % variable)中的%s表示一个占位符,variable是一个包含字符串的变量。这样,print函数会将字符串中的占位符替换为变量的值。 总结起来,print函数用于将文本或变量输出到控制台,它可以通过括号将要打印的内容括起来,还可以使用格式化字符串来打印变量的值。在Python 2.x版本中,print是一个语句,在Python 3.x版本中,print是一个函数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Python基础(九)——print函数详解,配合参数示例详解](https://blog.csdn.net/qq_42659468/article/details/118650165)[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* *3* [详解Python Print函数](https://blog.csdn.net/2301_77669908/article/details/130406031)[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 ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序喵正在路上

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

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

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

打赏作者

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

抵扣说明:

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

余额充值