Python基础-9.函数

TOC

一、函数基础

我们将常用的代码以固定的格式封装(包装)成一个独立的模块,只要知道这个模块的名字就可以重复使用它,这个模块就叫函数。

函数的定义

你可以定义一个由自己想要功能的函数,以下是简单的规则:
函数代码块以def关键词开头,后接函数标识符名称和圆括号()
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号 : 起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的return相当于返回None
语法:

def 函数名(参数列表):
    函数体
# 函数调用
函数名(参数列表)

1.无参函数

无参函数的意思就是该函数不需要传递任何参数。
【示例1】创建一个无参函数

def main():
    print('你调用了main函数.')

【示例2】创建一个无实际意义的无参函数

def main():
    pass

使用pass关键字直接跳过,该函数就是一个空函数,没有任何意义

2.有参函数

有参函数的意思跟无参函数相反,就是调用该函数需要传递参数。
【示例】创建一个比较大小的函数

def max_x_y(x, y):
    if x > y:
        print('x > y')
    else:
        print('y > x')

3.有返回值函数

又返回值函数就是该函数你定义了returen返回了一个值。
【示例】计算面积函数

def area(width, height):
    area_num = width * height
    return area_num  # 返回area_num变量

函数调用

调用函数也就是执行函数。如果把创建的函数理解为一个具有某种用途的工具,那么调用函数就相当于使用该工具。
定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过函数名调用执行,也可以直接从 Python 命令提示符执行。
【示例1】函数编写和调用

def hanshu():
    print('你已经调用了hanshu函数')


hanshu()

有返回值的函数调用
当你在函数中定义了一个return返回值的时候,我们可以把该函数赋值给一个变量,这样函数会直接被调用。
【示例】使用上面的计算面积函数举例

def area(width, height):
    area_num = width * height
    return area_num


# 我们直接把函数当成值
print('第一次计算的面积为:', area(4, 5))
# 我们通过赋值调用函数
a = area(5, 6)
print('第二次计算的面积为:', a)
'''运行结果如下
第一次计算的面积为: 20
第二次计算的面积为: 30
'''

这两种方式都能正常调用函数,把函数赋值给变量也会调用函数。

参数传递

以下是调用函数时可使用的正式参数类型:

  • 1.必需参数
  • 2.关键字参数
  • 3.默认参数
  • 4.不定长参数

温馨提示:当参数很多的时候建议使用关键字参数。

1.必需参数

必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
【示例】设定string为必须参数

def canshu(string):
    print('传递的参数:', string)


canshu('sdi4h28udh6uf7hdu')

注意:不加参数会报错!

2.关键字参数

关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为Python解释器能够用参数名匹配参数值。
【示例】

def guanjianzi(x, y):
    print('x的值为:', x, 'y的值为:', y)


guanjianzi(y='sdj3gg56jh6', x='dsj2345uh4f2')

3.默认参数

默认参数,不需要传递进去。
【示例】设定b为默认参数

def moren(a, b=27):
    c = a + b
    return c


print('c的值为:', moren(4))

4.不定长参数

你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。
加了星号*的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
加了两个星号**的参数会以字典的形式导入。

def printinfo(arg1, *vartuple):
    print("arg1的值:", arg1, 'vartuple的值:', vartuple)


# 调用printinfo函数,输出结果为 arg1的值: 70 vartuple的值: (60, 50)
printinfo(70, 60, 50)

补充说明:强制位置参数:如果单独出现星号*,则星号*后的参数必须用关键字传入。
/符号用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。

【示例】形参a和b必须使用指定位置参数,c或d可以是位置形参或关键字形参,而e和f要求为关键字形参。

def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)


f(10, 20, 30, d=40, e=50, f=60)      # 这是正确的使用方法
f(10, b=20, c=30, d=40, e=50, f=60)  # b 不能使用关键字参数的形式
f(10, 20, 30, 40, 50, f=60)          # e 必须使用关键字参数的形式

二、函数进阶概念

变量的作用域

所谓变量的作用域(Scope),就是变量的有效范围,也就是变量可以在什么范围内进行使用。变量的定义位置决定变量的作用域,不同位置的变量作用域不同,我们可以把这种概念分为局部变量全局变量

1.局部变量

什么是局部变量?
在函数内部定义的变量,只能在函数内部使用,不能在函数以外的部分使用。我们将这样的变量称为局部变量(Local Variable)。

当函数被执行时,Python会为其分配一块临时的存储空间,所有在函数内部定义的变量,都会存储在这块空间中。而在函数执行完毕后,这块临时存储空间随即会被释放并回收,该空间中存储的变量自然也就无法再被使用。
【示例】在函数内定义一个变量,函数内外部同时使用

def demo():
    a = 18.8
    print('函数内部使用,a的值:', a)

demo()
print('函数外部使用,a的值:', a)
'''运行结果如下
Traceback (most recent call last):
  File "/.../test.py", line 6, in <module>
    print('函数外部使用,a的值:', a)
NameError: name 'a' is not defined
函数内部使用,a的值: 18.8
'''

当我们遇到有参函数的时候,函数的参数也属于局部变量。
【示例】传参调用函数,并在函数内外部同时使用

def demo(a):
    print('函数内部使用,a的值:', a)

demo('hello')
print('函数外部使用,a的值:', a)
'''运行结果如下
Traceback (most recent call last):
  File "/.../test.py", line 5, in <module>
    print('函数外部使用,a的值:', a)
NameError: name 'a' is not defined
函数内部使用,a的值: hello
'''

总结:在函数内定义的变量和调用函数时传入的参数都是局部变量,只能在函数内容使用,外部使用会抛出异常报错。

2.全局变量

什么是全局变量?
在所有函数的外部定义变量,全局变量既可以在各个函数的外部使用,也可以在各函数内部使用。这样的变量称为全局变量(Global Variable)。

全局变量的定义分为两种。
函数外部定义
在函数外部定义的变量,一定是全局变量。
【示例1】代码如下:

a = 100

def demo():
    print('第一种方法,函数内部使用,a的值:', a)

demo()
print('第一种方法,函数外部使用,a的值:', a)
'''运行结果如下
第一种方法,函数内部使用,a的值: 100
第一种方法,函数外部使用,a的值: 100
'''

函数内部global关键字修饰定义
【示例2】基于之前的局部变量的函数进行修改,加上global关键字进行修饰

def demo():
    global a
    a = 18.8
    print('第二种方法,函数内部使用,a的值:', a)

demo()
print('第二种方法,函数外部使用,a的值:', a)
'''运行结果如下
第二种方法,函数内部使用,a的值: 18.8
第二种方法,函数外部使用,a的值: 18.8
'''

使用global关键字在函数内部对变量进行修饰之后,该变量被定义为全局变量,可以在函数外部进行正常使用了。

获取指定作用域范围中的变量

当我们需要获取某个作用域内(全局范围内或者局部范围内)所有的变量,Python提供了以下3种方式。

1.globals()函数

globals()函数是Python的内置函数,它的作用就是返回一个包含所有全局范围内的所有变量的字典。该字典键为变量名,键值为变量的值。
【示例】获取所有的全局变量

# 全局变量
a, b = 'aaa', 'bbb'

def demo():
    # 局部变量
    c, d = 18, 43

print('globals函数获取的值:',  globals())
print('a变量的值:', globals()['a'])
print('b变量的值:', globals()['b'])
'''运行结果如下
globals函数获取的值: {..., 'a': 'aaa', 'b': 'bbb', ...}
a变量的值: aaa
b变量的值: bbb
'''

2.locals()函数

locals()函数也是Python的内置函数,使用该函数也可以返回一个字典,该字典里面包含了所有局部变量。使用方法跟globals()函数一样,键为变量名,键值为变量的值。
【示例】获取所有的局部变量

# 全局变量
a, b = 'aaa', 'bbb'

def demo():
    # 局部变量
    c, d = 18, 43
    print('locals函数获取的值:',  locoals())
    print('c变量的值:', locals()['c'])
    print('c变量的值:', locals()['d'])

demo()
'''运行结果如下
locals函数获取的值: {..., 'c': 18, 'd': 43, ...}
c变量的值: 18
c变量的值: 43
'''

补充说明:当使用locals()函数获取所有全局变量时,和globals()函数一样,其返回的字典中会默认包含有很多变量。locals()返回的局部变量组成的字典,可以用来访问变量,但无法修改变量的值。

3.vars(object)

vars()函数的作用是返回一个指定object对象范围内所有变量组成的字典。如果不传入object参数,vars()locals()的作用完全相同。
【示例】

# 全局变量
a, b = 'aaa', 'bbb'

class demo:
    # 局部变量
    c, d = 18, 43

print('有object,vars获取:', vars(demo))
print('无object,vars获取:', vars())
'''运行结果如下
{..., 'c': 18, 'd': 43, ...}  
{..., 'a': 'aaa', 'b': 'bbb', ...}
'''

局部函数

在函数内部定义的变量叫局部变量,那么在函数内部定义的函数就叫局部函数(Python支持在函数内部定义函数)。
【示例1】在函数定义一个函数

# 全局函数
def a():
    # 局部函数
    def b():
        print('我是a函数内部的b函数.')
    b()  # 调用局部函数

a()  # 调用全局函数
'''运行结果如下
我是a函数内部的b函数.
'''

通过将局部函数作为所在函数的返回值,也可以扩大局部函数的使用范围。
【示例2】在全局函数中将局部函数作为返回值

# 全局函数
def a():
    # 局部函数
    def b():
        print('我是a函数内部的b函数.')
    return b  # 返回局部函数b函数

c = a()
c()
'''运行结果如下
我是a函数内部的b函数.
'''

三、匿名函数

Python中使用lambda关键字来创建匿名函数。所谓的匿名函数就是不再使用def关键字来定义一个函数。我们可以用匿名函数来定义一些简单的表达式函数。

简单使用

lambda使用规则:

  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  • lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然lambda函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,内联函数的目的是调用小函数时不占用栈内存从而减少函数调用的开销,提高代码的执行速度。

语法:

lambda 参数列表: 逻辑表达式

下面使用三个示例来演示使用lambda函数,不传参数、传入单个参数、传入多个参数的使用。
【示例1】不加参数列表

a = 10
add = lambda: a + 100
print(add())
'''运行结果如下
110
'''

【示例2】设置单个参数

add = lambda a: a + 25
print(add(25))
'''运行结果如下
50
'''

【示例3】设置多个参数

add = lambda a, b: a + b
print(add(18, 29))
'''运行结果如下
47
'''

其他使用

与内置函数如:map()filter()reduce()一起使用,以便在集合上执行操作。
【示例1】和map()函数结合使用,依次求出列表所有值的平方

numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
print(squared)
'''运行结果如下
[1, 4, 9, 16, 25]
'''

【示例2】和filter()函数一起使用,筛选出列表中的偶数

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)
'''运行结果如下
[2, 4, 6, 8]
'''

【示例3】和reduce()函数一起使用,计算一个序列的累积乘积

from functools import reduce

numbers = [1, 2, 3, 4, 5]
# 使用 reduce() 和 lambda 函数计算乘积
product = reduce(lambda x, y: x * y, numbers)
print(product)
'''运行结果如下
120
'''