目录
一、函数
1、定义
将具体功能封装起来,以便在程序的其它地方重复使用。这有助于代码的模块化和可维护性。
2、优势
-
减少代码的重复性
-
使代码的可读性更好
3、函数、方法、关键字区别
函数:封装有独立的功能,可以直接调用。后面需要跟()
方法:通过对象调用,主要针对这个对象进行的操作,后面也需要跟()
关键字:是 Python 中的保留词,具有特定的含义和功能。不能将关键字用作标识符(如变量名或函数名)。
4、基本语法
def 函数名(): # defined 定义的意思
函数体 # 没有内容使用 pass 占位符,跳过不会报错;缩进一般是四个空格
(1)def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。
(2)def:是固定的,不能变,它就是定义函数的关键字。
(3)空格:为了将 def 关键字和函数名分开,必须空,当然可以空2格、3格或者想空多少都行,但正常还是空1格。
(4)函数名:只能包含字母、下划线和数字且不能以数字开头。虽然函数名可以随便起,但给函数起名字还是要尽量简短,并且要具有可描述性。
def funa():
print('哈哈哈')
5、调用
函数名()
(1)函数名加小括号就可以调用了,这个时候函数的函数体会被执行。
(2)只有解释器读到函数名()
时,才会执行此函数,如果没有这条指令,函数里面即使有10万行代码也是不执行的。
(3)而且这个指令写几次,函数里面的代码就运行几次。
(4)每次调用函数时,函数都会从头开始执行,当这个函数中的代码执行完毕后,意味着调用结束了。
def funa():
print('哈哈哈')
funa()
注意:
函数必须先创建才可以使用,该过程称为函数的定义。
函数创建后可以使用,使用过程称为函数的调用。
二、函数返回值
1、定义
函数返回的值被称为返回值,return 函数的返回值返回给了函数名()
这个整体。
2、return 作用
(1)return 会给函数的执行者返回值,但是返回的结果不能输出到控制台(也就是不能直接打印出来),需要通过 print 才能打印出来。
如果 return 后面什么都不写,或者函数中没有 return,则返回的结果是 None
如果 return 后面写了一个值,返回给调用者这个值
如果 return 后面写了多个结果,返回给调用者一个 tuple (元组),调用者可以直接使用元组的解构获取多个变量
def funa():
a = 10
return a # 函数执行完之后会有一个结果,就可以用 return 返回出来
funa() # 不会被打印,函数的调用之后,执行了就会有一个结果
print(funa()) # 10
print(funa()) # 10
- return 后面可以是元组、列表、字典、函数等任意对象
- 只要是能够存储多个数据的类型,就可以一次性返回多个数据
- 如果返回多个值,是以元组的形式返回的。
def funa():
a = 10
b = [1, 2]
c = {'name': 'zs'}
return a, b, c
fn = funa()
print(fn) # (10, [1, 2], {'name': 'zs'})
print(type(fn)) # <class 'tuple'>
(2)函数中遇到 return,此函数结束,不再继续执行。
一个函数中可以有多个 return 语句,但是只要有一个 return 语句被执行到,那么这个函数就会结束了,因此后面的 return 没有什么用处。
def funa():
return 2
return 3
print(funa()) # 2
3、return 与 print 区别
-
return 之后的语句不执行,print 会一直执行。
-
print 用于输出内容到控制台,仅用于显示信息,不返回值。它不会影响程序的执行流程。
-
return 用于从函数中返回一个值,并终止函数的执行。它会将结果传递回调用函数的地方,可以用于在程序中进行计算和逻辑操作。
三、函数的参数
函数名后面括号里面的就是用来定义参数的。如果有多个参数,就用逗号进行隔开,函数定义了参数,那么调用函数的时候就需要传入参数。
1、分类
1.1、形参
写在函数声明的位置的变量叫形参,形式上的一个完整。定义时小括号中的参数,用来接收参数用的,仅在函数体内有效。
1.2、实参
在函数调用的时候给函数传递的值叫实参。实际执行的时候给函数传递的信息,调用时小括号中的参数,用来传递给函数用的。
函数的传参就是函数将实际参数交给形式参数的过程。
# 参数能够接受任意类型的对象
def funa(name): # 函数定义时(参数) 这个就是形参
print('%s你好' % name)
funa('张三') # 函数执行时(参数) 这个就是实参
这个过程就是:-
代码运行到funa('张三')
开始执行此函数-
同时将字符串'张三'
这个数据传递给变量 name-
然后执行函数中的代码,如果遇到 name,其实就是使用'张三'
这个数据
def add(a, b):
print(a+b)
add(2, 3) # 5 调用带有参数的函数时,需要在小括号中,传递数据
2、位置参数(必备参数)
位置参数是按照参数列表的顺序传递给函数的参数。函数在调用时需要按照定义的顺序传递相应数量的参数。位置参数在函数体内部通过名称访问。
写了几个,就必须要传几个,不然会报错,调用时按照参数的位置顺序,依次赋予参数值。
def funb(a, b):
result = a - b
print(result)
funb(3, 1) # 2
funb(3) # TypeError: funb() missing 1 required positional argument: 'b'
3、默认参数(缺省参数)
默认参数在函数定义时指定一个默认值,如果在函数调用时没有提供相应参数,将使用默认值。默认参数通常在参数列表的末尾定义。
在函数声明的时候,就可以给出函数参数的默认值。默认值参数一般是这个参数使用率较高,才会设置默认值参数。
def funa(a=12):
print('%s哈哈哈'%a)
funa() # 12 如果没传值,就按默认的参数去执行
funa(15) # 15 如果传了值,就按传的参数去执行
注意: 带有默认值的参数一定要位于参数列表的最后面。
4、不定长参数
有时需要一个函数处理多个数据,这时用到多值参数。
在参数前加一个 *
可以接收元组,加 **
可以接收字典。
一般用 *args
存放元组参数,用 **kwargs
存放字典参数。
4.1、可变参数
传入的参数数量是可变的,传入的数量可以是任意多个,但也可以没有。
args 就是一个普通的形参,但是如果在 args 前面加一个 *
,那么就拥有了特殊的意义,它是有魔法的。
def funa(*args): # 接收多个值,都是以元组接收的
print(args)
print(type(args))
funa(1,2,3)
# 运行结果:
# (1, 2, 3)
# <class 'tuple'>
这样设置形参,那么这个形参会将实参所有的位置参数接收,放置在一个元组中,并将这个元组赋值给 args 这个形参,这里起到魔法效果的是 * 而不是 args,a 也可以达到这个效果,但是 PEP8 规范中规定就使用 args,约定俗成的。
def funa(*a):
print(a)
print(type(a))
funa('a', 'b', 'c')
# 运行结果:
# ('a', 'b', 'c')
# <class 'tuple'>
4.2、关键字参数
** kwargs,同理这个 **
也是具有魔法用法的,kwargs 约定俗成使用作为形参。
** kwargs,是接收所有的关键字参数,然后将其转换成一个字典赋值给 kwargs 这个形参。 关键字参数也允许传入0个或者任意个含参数名的参数,这些关键字参数会在函数内部自动组装为一个 dict。
def funa(**kwargs): # 关键字传参
print(kwargs)
print(type(kwargs))
funa(a='ss',b=12) # 键等于值的形式
# 运行结果:
# {'a': 'ss', 'b': 12}
# <class 'dict'>
def funa(**b):
print(b)
print(type(b))
funa(name='zs', age=18)
# 运行结果:
# {'name': 'zs', 'age': 18}
# <class 'dict'>
5、混合参数
参数定义顺序:-
位置参数(必备参数)、默认参数(缺省参数)、可变参数(*args)、关键字参数(** kwargs)
*args
必须在**kwargs
前面
如果很多个值都是不定长参数,那么这种情况下,可以将缺省参数放到 *args 的后面, 但如果有 ** kwargs 的话, ** kwargs 必须是最后的。
# 例一:
def funa(a, b=10, *c): # 必备 默认 可变
print(a, b, c)
funa(1, 2, 3, 4)
# 运行结果:
# 1 2 (3, 4)
# 例二:
def funb(a, *c, b=20): # 必备 可变 默认
print(a, c, b)
funb(1, 2, 3, 4)
# 运行结果:
# 1 (2, 3, 4) 20
# 例三:
def func(a, b=20, *c, **d): # 必备 默认 可变 关键字
print(c, d)
print(a, b)
func(1, 2, 3, 4, na='as', age=12)
# 运行结果:
# (3, 4) {'na': 'as', 'age': 12}
# 1 2
四、函数嵌套
函数的嵌套,就是一个函数中还有函数。
使用嵌套函数的情况
-
封装 - 数据隐藏
-
贯彻 DRY 原则,嵌套函数,可以在函数内部避免重复代码。
-
闭包:闭包、装饰器这些高级用法跟嵌套函数紧密相关。
DRY(Don’t Repeat Yourself)
是指在程序设计以及计算中避免重复代码,因为这样会降低灵活性、简洁性,并且有可能导致代码之间的矛盾。DRY 更多的是一种架构设计思想,在软件开发过程中的万事万物均可能重复,大到标准、框架、开发流程;中到组件、接口;小到功能、代码均存在自我重复。而 DRY 提倡的就是在软件开发过程中应消除所有这些自我重复。
嵌套调用:在一个函数里面调用别的函数。
def funa():
print('这是funa')
def funb():
print('这是funb')
funa()
funb()
# 运行结果:
# 这是funb
# 这是funa
嵌套定义:在一个函数中定义了另外一个函数。在外函数内部调用内函数,即用函数名调用。
def funa():
def funb():
print('这是funb')
print('这是funa')
funb() # 函数名调用内函数
funa()
# 运行结果:
# 这是funa
# 这是funb
可以用 return 调用内函数
def funa():
print('这是外部函数')
def funb():
print('这是内部函数')
return funb()
funa()
# 运行结果:
# 这是外部函数
# 这是内部函数
五、代码练习
1、写一个函数求三个数的和
def calculate_sum(a, b, c):
total = a + b + c
return total
num1 = 5
num2 = 10
num3 = 3
result = calculate_sum(num1, num2, num3)
print(f"{num1} + {num2} + {num3} = {result}") # 5 + 10 + 3 = 18
2、求这个三个数的平均值
def calculate_average(a, b, c):
total = a + b + c
average = total / 3
return average
num1 = 5
num2 = 10
num3 = 3
average_result = calculate_average(num1, num2, num3)
print(f"{num1}, {num2}, {num3} 的平均数是 {average_result}") # 5, 10, 3 的平均数是 6.0
3、接收n个数字,求这些参数数字的和
# 思路:
# 1.定义函数
# 2.接收数字,不知道多少个,用 *args
# 3.计算累积和,需要两个数相加
# 4.传值计算以后,返回结果
# 5.调用函数,需要 print 输出结果
def calculate_sum(*numbers):
total = sum(numbers)
return total
num1 = 5
num2 = 10
num3 = 3
result = calculate_sum(num1, num2, num3)
print(f"{num1} + {num2} + {num3} = {result}") # 5 + 10 + 3 = 18
num4 = 8
num5 = 12
result_with_more_numbers = calculate_sum(num1, num2, num3, num4, num5)
print(f"{num1} + {num2} + {num3} + {num4} + {num5} = {result_with_more_numbers}") # 5 + 10 + 3 + 8 + 12 = 38
4、打印自定义行数的横线
def print_horizontal_lines(lines):
for _ in range(lines):
print("-----------")
line_count = 3 # 指定行数
print_horizontal_lines(line_count)
5、实现摇骰子的功能,打印N个骰子的点数和
import random
def roll_dice():
return random.randint(1, 6) # 随机生成1到6之间的整数,模拟骰子点数
def roll_and_sum_dice(num_dice):
total_sum = sum([roll_dice() for _ in range(num_dice)])
return total_sum
num_dice = 3 # 指定骰子数量
result = roll_and_sum_dice(num_dice)
print(f"{num_dice} 个骰子点数和为 {result}")
6、写一个能够让列表从大到小排序的函数
使用 sorted() 函数对列表进行排序,并通过
reverse=True
参数来实现从大到小的排序,去掉 reverse=True 为从小到大的排序。
# 改变原始列表
number_list = [5, 3, 9, 1, 7, 2] # 测试列表
number_list.sort(reverse=True)
print(number_list) # [9, 7, 5, 3, 2, 1]
# 不改变原始列表
def sort_descending(numbers):
sorted_list = sorted(numbers, reverse=True)
return sorted_list
number_list = [5, 3, 9, 1, 7, 2] # 测试列表
sorted_descending = sort_descending(number_list)
print(number_list) # [5, 3, 9, 1, 7, 2]
print(sorted_descending) # [9, 7, 5, 3, 2, 1]
7、求出列表里面的最大值和最小值(不用min和max)
def find_min_max(numbers):
if not numbers:
return None, None
min_value = numbers[0]
max_value = numbers[0]
for num in numbers:
if num < min_value:
min_value = num
if num > max_value:
max_value = num
return min_value, max_value
# 测试列表
number_list = [5, 3, 9, 1, 7, 2]
min_val, max_val = find_min_max(number_list)
print(f"最小值是: {min_val}")
print(f"最大值是: {max_val}")
在函数中使用
return None, None
的语法是为了返回一个元组,其中包含两个 None 值。这样的语法在返回多个值时是一种常见的做法,即使其中某些值可能是 None 或其它特定的默认值。在上面的示例中,find_min_max 函数可能会遇到传入空列表的情况,此时无法找到最小值和最大值。为了在这种情况下返回明确的结果,使用了 None, None 来表示不存在最小值和最大值。这样,函数的调用者可以根据返回值是否为 None 来判断是否成功找到最小值和最大值。
例如,调用 find_min_max([]) 将返回 (None, None),而调用 find_min_max([5, 10, 3]) 将返回 (3, 10)。
总之,return None, None 是为了在函数中返回一个表示特定情况的元组,其中的值为 None。