目录
前言
当需要频繁使用某段具备相同功能的代码块来编写项目实现代码时,可以使用自定义函数来替代。建设重复编写相同功能代码块的麻烦。
一、函数的创建
1、介绍函数
在Python中可以使用代码dir(__builtins__)获取Python中的全部函数。这些函数具有特定的功能,但在实际开发中这些函数的功能不一定能完全满足项目的需求,因此Python提供了一种可以让用户自己定制函数的方法来满足项目的不同需求,并且可以直接使用函数名来替代整个代码块,大大减少了重复编写相同代码块的烦琐工作。
需要注意区分定义函数和调用函数,定义函数是指创建一个新的函数,调用函数是指使用这个函数.例如函数print(参数)是已经被Python创建好的一个内置函数(已经定义好的函数),前几章内容中使用到的print()函数是调用函数,print是该函数的名称(即函数名)。
dir(__builtins__)
#输出
#['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
2、函数的定义
创建新函数
def 函数名(参数):
代码块
return 返回值
示例(输出数字0-9)
def fun1():
for i in range(10):
print(i,end='')
#没有输出
3、函数的调用
代码必须调用才能执行,创建函数代码需在调用函数的代码上方
def fun1():
for i in range(10):
print(i,end='')
print(fun1())
#输出0123456789None
调用print(fun1())
,由于fun1
函数没有返回值,默认返回None
,所以先执行fun1
函数打印 0 到 9,然后打印None
。
4、函数的复用
定义函数最大的优点就是不需要重复编写复杂的代码块,提高代码编写效率
例1,求阶乘之和
def fun3(n):
b = 1
for i in range(1,n+1):
b = int(i)*b
print(i, b)
return b
b = fun3(7)+fun3(8)+fun3(9)
print(b)
#输出
# 1 1
# 2 2
# 3 6
# 4 24
# 5 120
# 6 720
# 7 5040
# 1 1
# 2 2
# 3 6
# 4 24
# 5 120
# 6 720
# 7 5040
# 8 40320
# 1 1
# 2 2
# 3 6
# 4 24
# 5 120
# 6 720
# 7 5040
# 8 40320
# 9 362880
# 408240
例2,求平均成绩
def fun5(name,math,computer):
average = (math+computer)/2
print(name,':\t数学成绩:',math,'\t计算机成绩:',computer,'\t平均成绩:',average)
fun5('张三',90,89)
fun5('李四',98,84)
fun5('王五',91,80)
# 输出
# 张三 : 数学成绩: 90 计算机成绩: 89 平均成绩: 89.5
# 李四 : 数学成绩: 98 计算机成绩: 84 平均成绩: 91.0
# 王五 : 数学成绩: 91 计算机成绩: 80 平均成绩: 85.5
5、retur返回值
return语句的4种使用方式
1、定义函数中带return语句,返回数据到调用函数
def fun3():
ls = ['张三','李四','王二麻子']
a = len(ls)
return a
print(fun3())
# 输出:3
2、定义函数中不带return语句,调用函数默认接受到一个空值即None
def fun1():
for i in range(12):
print(i,end='-')
print(fun1())
# 输出0-1-2-3-4-5-6-7-8-9-10-11-None
3、定义函数中带return语句且返回多个值,一般以元组的形式返回所有值
def fun3():
ls = ['张三','李四','王二麻子']
a = len(ls)
b = ls.pop()
return a,b
print(fun3())
# 输出(3, '王二麻子')
4、定义函数中return语句位于非末尾行且返回多个值,但执行到第一个即退出
def fun2():
ls = ['张三','李四']
a = len(ls)
print(a)
b = ls.pop(0)
print(b)
print(ls)
c = ls.pop()
print(ls)
return a, b, c
print(fun2())
# 输出
# 2
# 张三
# ['李四']
# []
# (2, '张三', '李四')
二、函数的参数
1.形参和实参
创建函数时可以设置函数接收多个参数,例如调用print()
函数时可以填入多个参数。定义函数中的参数被称为形参(形式参数),调用函数时填入的参数被称为实参(实际参数)。形参和实参的使用形式如下:
def 函数名(形参1, 形参2, ...):
代码块
return 返回值
函数名(实参1, 实参2, ...)
在使用实参和形参时,需要了解其使用形式的相关描述
1、形参使用变量名来接收实参传递过来的信息,一次形参1、形参2都为变量名。
2、在创建函数时,需要确定函数需要处理的数据有哪些,从而确保形参的个数。
3、当函数需要接收多个形参时,形参之间要使用逗号隔开。
4、调用函数中的实参为实际数据,且实参的个数要和形参的个数相同。
5、调用函数时会按照顺序依次将所有实参的数据复制给形参。
def fun3(n):
b = 1
for i in range(1, n+1):
b = int(i) * b
return b
a = input("请输入一个数字:")
print(a, '的阶乘:', fun3(int(a)))
# 输出示例
# 请输入一个数字:5
# 5 的阶乘: 120
2、默认参数
在通常情况下,定义函数中的某些参数会填入相同的数据,这时可以给参数设置默认参数,即提前给参数设置一个数据。设置默认参数的使用形式如下:
def 函数名(形参1, 形参2=数据2):
代码块
return 语句
给定义函数设置默认参数前,也需要了解其使用形式和相关描述:
1、在定义函数的形参中,“形参2=数据2” 表示将数据2(数据 2 为具体的一个数据值)赋给形参2,形参2也被称为默认参数。
2、默认参数的功能是当调用函数没有填入实参2的数据时,形参2默认填入数据2的值。在每次调用函数时,如果填入的形参数据值都是固定的,可以将此形参设置为默认参数,而相应实参则不用再填入数据值。
3、当调用函数传递了实参2的数据值时,实参2的数据值将覆盖数据2的值。
def circle_s(r, pi=3.14):
return r*r*pi
a = circle_s(3)
b = circle_s(5)
print(a+b)
# 输出:106.76
3、可变参数
不确定函数中需要接受的参数个数时,可以使用可变参数,只需在形参前加一个*
形式
def 函数名(形参1, *形参2):
1、可变参数的形参使用*
开头。
2、可变参数必须位于必填参数的右边以保证必填参数先接收到数据,再将剩余的数据传递给可变参数。
3、可变参数以元组的形式接收数据。
def fun3(a, *b):
print(b)
c = 0
for i in b:
c += a*i
return c
print(fun3(3,1,2,3))
# 输出:
# (1, 2, 3)
# 18
4、关键字参数
关键字参数以字典形式接收数据,形参使用双星号(**)开头,必须位于必填参数右侧。
实参传递时需以键值对形式(如 key=value)传递给关键字参数,剩余参数会自动收集到关键字参数字典中。
def 函数名(形参1, **形参2):
1、关键字参数的形参使用**
开头。
2、关键字参数必须位于必填参数的右边,从而保证必填参数会先接收到数据,再将剩余数据传递给关键字参数。
3、关键字参数以字典的形式接收数据。
4、传递给关键字参数的数据包含键和值,其中键和值之间使用等号连接。
def fun4(a,**b):
print(a,'课程考试成绩:')
print(b)
fun4('Python',zhangsan=90,lisi=95)
# 输出:
# Python 课程考试成绩:
# {'zhangsan': 90, 'lisi': 95}
三、函数变量的作用范围
根据变量的作用范围可以将变量分为全局变量和局部变量。全局变量指变量在整个代码文件内部都可以被使用,局部变量指变量只能在局部范围内被使用。函数中的形参变量和函数内部代码块中的变量都是局部变量。
def fun5(a,b,c=10):
d = a*a+b*b+c*c
return d
fun5(1,2,3)
print(a)
# 输出
# Traceback (most recent call last):
# File "C:\Users\31253\Desktop\学徒\工程\2\7-7\12.py", line 5, in <module>
# print(a)
# NameError: name 'a' is not defined
第1~3行代码创建了一个函数fun5(),在fun5()中有形参变量a、b、c,但a、b、c都只能在fun5()函数内部使用,因此在执行第5行代码时print(a)会出现异常错误,因为在fun5()函数外部的代码中并没有对变量a进行赋值,即没有定义变量a。
注意,定义函数fun5()中创建了一个变量d,变量d也属于局部变量,只能在fun5()函数内部使用。
全局变量可以在整个代码文件范围内被使用,函数内部代码也可以使用外部定义的全局变量
def fun5(a,b,c=10):
d = a*a+b*b+c*c+e
return d
e = 100
print(fun5(1,2,3))
# 输出:114
1.函数中使用全局变量存在的问题
当在函数中使用全局变量且对全局变量进行了赋值时,将会重新在函数内部创建一个新的局部变量,而不是直接使用全局变量。
定义函数中的变量a并不是函数内部的变量,因为函数的外部代码对变量a进行了赋值,a 属于全局变量,所以函数可以直接使用全局变量a。
def fun7(b):
print('a+b的值:',a+b)
print('a+b的值:',a+b)
a = 3
fun7(13)
print('a的值:',a)
# 输出:
# a+b的值: 16
# a+b的值: 16
# a的值: 3
在函数内部对a进行新的赋值:
def fun7(b):
print('a+b的值:',a+b)
a = 2
print('a+b的值:',a+b)
a = 3
fun7(13)
print('a的值:',a)
# 输出
# Traceback (most recent call last):
# File "C:\Users\31253\Desktop\学徒\工程\2\7-7\13.py", line 6, in <module>
# fun7(13)
# File "C:\Users\31253\Desktop\学徒\工程\2\7-7\13.py", line 2, in fun7
# print('a+b的值:',a+b)
# UnboundLocalError: local variable 'a' referenced before assignment
结果中的报错信息提示在函数中局部变量a没有分配值,这是因为在函数中对a重新赋值时,系统默认在函数中创建了一个局部变量a,a的值为2。因为第2行代码中并没有a的任何赋值信息,也不会使用到全局变量的值,所以执行代码后出现了错误。
def fun7(b):
a = 2
print('a+b的值:',a+b)
a = 3
fun7(13)
print('a的值:',a)
# 输出:
# a+b的值: 15
# a的值: 3
2.global声明全局变量
如果需要在函数外部和函数内部都使用同一个变量(不会因为在函数内部而被重新赋值),可以在函数中使用global函数对变量进行声明。
def fun7(b):
global a
print('a的值:', a)
a = 2
print('a+b的值:',a+b)
a = 3
fun7(13)
print('a的值:',a)
# 输出:
# a的值: 3
# a+b的值: 15
# a的值: 2
第2行代码使用关键字global对变量a进行了声明,表示在函数中使用全局变量a,且两者为同一个数据,占用同一个内存空间。在该结果中,第1行为第3行代码输出的内容,表明a的值为全局变量a的值。而第4行代码对a进行了重新赋值,因此输出结果中的第 2 行内容表明a的值已经变为 2。输出结果中的第3行内容为第8行代码执行后的结果,表明函数内部对a的修改影响到了函数外部的a,也证明了函数内部和函数外部的变量a为同一个变量。
3.*变量为可变函数
在 Python 中根据是否会改变内存空间可将数据分为可变数据和不可变数据,其中可变数据是指数据变化后不会改变内存空间。在 Python中任何一个变量在运行过程中都会在内存中开辟一个空间来存储变量对应的数据值,可以通过id()函数获取当前变量的数据值所在的内存空间编号。
查询变量的内存空间编号:
a = 4
b = [2, 3]
print(id(a), id(b))
a = 5
b.append(5)
print(id(a), id(b))
# 输出:
# 2068692756880 2068699630656
# 2068692756912 2068699630656
执行后的数据结果可能与以上结果不同,因为每台计算机分配给变量的内存空间都是随机的,所以内存空间编号也会各不相同,甚至每次执行后的结果都会各不相同。通过上面的输出结果可以看出在经过第4、5行代码对变量的值进行改变后,只有变量a的内存空间编号改变了,而变量b的内存空间编号依旧是2506345107976。说明了变量b在通过方法(例如append()、pop()方法)修改值后,其内存空间始终保持不变。但是当直接对变量进行赋值时,其内存空间会被改变。
重新对列表b列表赋值,使得b的内存空间被改变:
a = 4
b = [2, 3]
print(id(a), id(b))
a = 5
b = [2, 3, 5]
print(id(a), id(b))
# 输出:
# 2107958847888 2107961963072
# 2107958847920 2107963165312
4.函数中的可变数据
当可变数据为全局变量时,在函数中对可变数据进行修改会改变全局变量。
def fun10():
a.reverse()
print(a)
a = [2,3,4]
fun10()
print(a)
# 输出:
# [4, 3, 2]
# [4, 3, 2]
由于函数中没有global声明,也没有用于改变变量a内存空间的代码,一次默认使用全局变量a。该结果表明函数内部输出的a和函数外部输出的a时相同的,即它们实际上时同一个变量。
在代码中多次调用具有可变数据的函数:
def func():
ls.append(1)
return ls
ls = []
a = func()
b = func()
print(a,b)
# 输出:[1, 1] [1, 1]
四、4导入其他模块的函数
1、导入文件模块
形式:
import 文件名(不需要文件扩展名)
文件名.函数名
注意:导入模块是指将整个模板文件复制到需要导入的代码文件中,若模块中除函数定义外还有其他代码,程序将按顺序执行
2、选择性导入文件中的函数
from 模块 import 函数:仅导入指定函数,减少资源占用。
from 模块 import *:导入全部函数(可直接调用函数名,无需前缀)
3、别名设置
通过as关键字为模块或函数设置别名(如import numpy as np)
4、__name__属性作用
用于区分模块是被导入还是直接运行:
直接运行时,__name__值为"__main__"。
被导入时,__name__值为模块文件名。
典型用途:将测试代码放入if __name__ == "__main__":中,避免被导入时执行。
五、匿名函数lambda的用途
①用于创建简单函数:
语法:函数名 = lambda 参数: 表达式(如add = lambda x, y: x + y),默认使用return返回
适用场景:功能简单且无需复用的情况。
②可作为函数参数,以sorted()为例