1、函数的定义和调用
函数是一种代码集合或语句组,可以执行一个特定的任务或模型。通过定义函数,多次调用该函数,实现代码的复用。定义函数的语法如下:
def 函数名(参数列表):
函数体(函数体前面有四个空格)
return [表达式](用来做返回值,可以没有,返回None)
# 函数的定义
def helloWorldPrint():
print("hello world")
# 函数的调用
helloWorldPrint()
# 带参数函数定义
def xPrint(str1):
print(str1)
# 函数调用
xPrint("hello world")
# 带返回值的函数
def xPrint(str1):
print(str1)
return str1
# 函数调用
str2 = xPrint("hello world")
print(str2) # 返回值的结果为:'hello world'
2、函数的注释和标注
函数的第一行语句可以选则性地使用“文档字符串”用于存放函数说明,一般第一行为对象目的的简要描述。第二行为空白,后面几行应该是一个或多个段落,描述对象的调用约定、副作用等。可以使用内置函数help()或者函数名.__doc__来查看函数的注释。
# 函数定义
def xPrint(str1):
'''函数的简要描述
函数参数str1:函数参数的描述
返回值 str1:返回值的描述
'''
print(str1)
return str1
# 打印函数文档字符串的两种方式
help(xPrint)
print(xPrint.__doc__)
函数和函数的形参都可以不指定类型,但是这样会导致在阅读程序或者函数调用时无法知道参数的类型。
Python提供“函数标注”的手段为形参标注类型。函数标注是关于用户自定义函数中使用的类型的元数据信息,它以字典的形式存放在函数的“__annotations__”属性中,并且不会影响函数的任何其他部分。
# 函数定义
def xPrint(str1)->str:
'''函数的简要描述
函数参数str1:函数参数的描述
返回值 str1:返回值的描述
'''
print("函数标注:",xPrint.__annotations__)
print(str1)
return str1
# 函数调用
xPrint("hello world") # 函数标注: {'return': <class 'str'>}
3、变量作用域
在函数内部或者外部,会经常用到变量。函数内部定义的变量一般为局部变量,函数外部定义的变量为全局变量。变量起作用的代码范围称为“变量的作用域”。
注意:变量的作用域都是从定义的位置开始,在定义前访问就会报错。在独立代码文件中,直接使用没有定义的变量,也会报错。
函数内定义的局部变量,其作用域仅在函数内:一旦函数运行结束,则局部变量都被删除而不可访问。
在函数内部可以通过global定义的方式来定义全局变量,该全局变量在函数运行结束后依然存在并可访问。
# 全局变量和局部变量
a,b = 'hello','world'
def xPrint():
a,b = 'a','b'
print("函数内部:",a,b)
return a,b
print("函数外部:",a,b) # 函数外部:hello world
xPrint() # 函数内部:a b
print("函数外部:",a,b) # 函数外部:hello world
# global定义全局变量
a,b = 'hello','world'
def xPrint():
global a
a,b = 'a','b'
print("函数内部:",a,b)
return a,b
print("函数外部:",a,b) # 函数外部:hello world
xPrint() # 函数内部:a b
print("函数外部:",a,b) # 函数外部:a world
4、函数的递归调用
递归是一种特殊的函数调用形式。函数在定义时直接或间接调用自身的一种方法,目的是将大型复杂的问题转化为一个相似的但规模比较小的问题。构成递归需要具备下面的条件:
子问题须与原来的问题为同样的问题,但规模较小或更为简单;
调用本身须有出口,不能无限制调用,既有边界条件。
# 求斐波那契数列:0,1,1,2,3,4,8,13......,定义如下:
# F(0)=0
# F(1)=1
# F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)
def fibonacci(n):
"求斐波那契数列中第n个元素"
fn = 0
if n==1:
fn = 0
elif n==2:
fn = 1
else:
fn = fibonacci(n-2) + fibonacci(n-1)
return fn
# 调用函数
print(fibonacci(5))
5、lambda表达式
用lambda表达式来简略定义函数,称为”匿名函数“,特点如下:
lambda表达式中只包含一个表达式,函数体比def简单很多,所以匿名函数更加简洁;
lambda表达式的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去;
lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
# 普通函数定义
def add(x, y):
return x + y
result = add(5, 3)
print(result) # 输出: 8
# lambda函数举例
add = lambda x, y: x + y
result = add(5, 3)
print(result) # 输出: 8
6、参数传递
在调用函数时,向函数传递实参,根据不同的实参参数类型,将实参的值或引用传递给形参。在Python中,各种数据类型都是对象,其中字符串、数字、元组等是不可变对象;列表、字典等是可变对象。对于Python函数在传递不可变对象和可变对象这两种参数时,变量的值和存储的地址变化举例。
# 给函数传递不可变对象
def modify_string(s):
s = "Hello, World!" # 尝试修改字符串,但实际上是创建了一个新的字符串对象
print("Inside function:", s)
original_string = "Hello, Python!"
modify_string(original_string)
print("Outside function:", original_string) # 输出: Hello, Python!
# 给函数传递可变对象
def modify_list(lst):
lst.append("new item") # 修改列表,添加一个新元素
print("Inside function:", lst)
original_list = [1, 2, 3]
modify_list(original_list)
print("Outside function:", original_list) # 输出: [1, 2, 3, 'new item']
7、参数类型
Python的函数中的参数类型包括位置参数、关键字参数、默认参数、不定长参数等。
# 位置参数,就是在函数调用时是必须有的,而且顺序和数量都要保持一致。
def add(x, y):
return x + y
add(1,3) # 1和3都是位置参数,缺一不可。
# 关键字参数
add(x=1,y=3) # x=1和y=3是关键字参数,两个参数的位置可以随意变换。
# 默认参数
def add_xyz(x,y,z=5):
return x+y+z
add_xyz(1,3) # z的值默认为5,即默认参数,该值可以不指定,也可以传入其他值。
add_xyz(1,3,2) # z的值为2
# 注意:默认参数是在函数定义的时候就计算的
z = 2
def add_xyz(x,y,z=z):
print(z)
return x+y+z
z = 3
add_xyz(1,3) # 打印的z的值为2
# 不定长参数
def func(*args, **kwargs):
print("Positional arguments:", args)
print("Keyword arguments:", kwargs)
func(1, 2, 3, a=4, b=5)
# 输出:
# Positional arguments: (1, 2, 3)
# Keyword arguments: {'a': 4, 'b': 5}
# 参数传递的解包,单个星号(*)对参数传递的序列解包。
def greet(first_name, last_name):
print(f"Hello, {first_name} {last_name}!")
# 有一个包含名字和姓氏的元组
person = ("Alice", "Wonderland")
# 使用序列解包将元组元素作为独立参数传递给greet函数
greet(*person)
# 输出: Hello, Alice Wonderland!
# 参数传递的解包,两个星号(**)对字典的值进行解包
def xPrint(a,b,c):
print(a,b,c)
return a,b,c
x = {'a':1,'b':2,'c':3}
xPrint(**x)
# 输出:1 2 3
# 注意,对字典类型数据解包的时候,键与形参一致。