在编程中,函数是非常重要的概念,它为我们提供了一种将复杂问题分解为较小、可管理部分的方法。以下将详细介绍函数的各个基础方面。
一、函数目的
通过包含函数,我们可以避免程序重复使用相同的代码块。
- 一旦定义,Python函数可以在程序中的任何位置多次调用。
- 如果有必要,我们的Python程序可以分解为多个易于遵循的函数。
- 使用各种参数,我们可以返回尽可能多的输出是Python最重要的成就之一。
- 然而,调用函数在Python程序中始终会产生开销。
二、函数定义
函数定义指定了函数的名称、参数和函数体。函数体包含了实现函数功能的具体代码。方便大家理解,这里有一个图和代码示例供大家参考。
这里就调用了函数输出30。
def add_numbers(a, b):
return a + b
print(add_numbers(10, 20)) # 30
三.形参与实参
- 形参(形式参数)是函数定义时指定的参数,用于在函数体内部接收数据。
- 实参(实际参数)是调用函数时传递给函数的值或变量。
# 使用形参与实参
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
# 只传递一个实参(name)
greet("Alice")
# 传递两个实参(name 和 greeting)
greet("Bob", "Hi")
四.函数的返回值
函数可以通过return
语句返回一个值给调用者。如果函数没有return
语句,则默认返回None
。
# 定义一个函数,计算并返回圆的面积
def calculate_area(radius):
return 3.14159 * radius * radius
# 调用函数并接收返回值
radius = 5
area = calculate_area(radius)
print(f"The area of the circle is: {area}")
五.函数的参数类型(Python的动态类型)
Python是动态类型语言,不需要在函数定义时指定参数类型。但可以使用类型提示(Type Hints)来提高代码的可读性和可维护性
# 使用类型提示定义函数
def multiply(a: int, b: int) -> int:
return a * b
# 调用函数
result = multiply(5, 3)
print(f"The product is: {result}")
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
-
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。
-
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
-
不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
-
可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
通过 id() 函数来查看内存地址变化:
def change(a):
print(id(a)) # 指向的是同一个对象
a=10
print(id(a)) # 一个新对象
a=1
print(id(a))
change(a)
形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id。
传可变对象实例
可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。
# 可写函数说明
def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print ("函数内取值: ", mylist)
return
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)
# 函数内取值: [10, 20, 30, [1, 2, 3, 4]]
# 函数外取值: [10, 20, 30, [1, 2, 3, 4]]
六.参数
以下是调用函数时可使用的正式参数类型:
- 必需参数
- 关键字参数
- 默认参数
- 不定长参数
必需参数
必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
调用 printme() 函数,你必须传入一个参数,不然会出现语法错误:
#可写函数说明
def printme( str ):
"打印任何传入的字符串"
print (str)
return
# 调用 printme 函数,不加参数会报错
printme()
# 例如
# Traceback (most recent call last):
# File "test.py", line 10, in <module>
# printme()
# TypeError: printme() missing 1 required positional argument: 'str'
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值:
#可写函数说明
def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )
以上实例输出结果:
名字: runoob
年龄: 50
------------------------
名字: runoob
年龄: 35
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述 2 种参数不同,声明时不会命名。基本语法如下:
def functionname([formal_args,] *var_args_tuple ):
"函数_文档字符串"
function_suite
return [expression]
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
# 可写函数说明
def printinfo( arg1, *vartuple ):
"打印任何传入的参数"
print ("输出: ")
print (arg1)
print (vartuple)
# 调用printinfo 函数
printinfo( 70, 60, 50 )
# 结果为:
# 输出:
# 70
# (60, 50)
还有一种就是参数带两个星号 **基本语法如下:
def functionname([formal_args,] **var_args_dict ):
"函数_文档字符串"
function_suite
return [expression]
加了两个星号 ** 的参数会以字典的形式导入。
# 可写函数说明
def printinfo( arg1, **vardict ):
"打印任何传入的参数"
print ("输出: ")
print (arg1)
print (vardict)
# 调用printinfo 函数
printinfo(1, a=2,b=3)
# 输出:
# 1
# {'a': 2, 'b': 3}
七.匿名函数
Python 使用 lambda 来创建匿名函数。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
- lambda 只是一个表达式,函数体比 def 简单很多。
- lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,内联函数的目的是调用小函数时不占用栈内存从而减少函数调用的开销,提高代码的执行速度。
语法
lambda 函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
设置参数 a 加上 10:
x = lambda a : a + 10
print(x(5))
# 5
以下实例匿名函数设置两个参数:
# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2
# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 ))
print ("相加后的值为 : ", sum( 20, 20 ))
# 相加后的值为 : 30
# 相加后的值为 : 40