文章目录
在实际开发过程中,经常会遇到很多完全相同或者非常相似的操作,这时,可以将实现类似操作的代码封装为函数,然后在需要的地方调用该函数。这样不仅可以实现代码的复用,还可以使代码更有条理性,增加代码的可靠性。
函数是一段具有特定功能的、可重复使用的代码段,它能够提高程序的模块化和代码的复用率。
Python提供了很多内建函数(如print()、input()、int()函数等)
标准库函数(如math库中的sqrt()函数)
用户还可以自己编写函数,称为自定义函数。
1.函数的定义和使用
1.1函数的定义
在Python中,定义函数的一般形式为:
def 函数名([形式参数列表]):
函数体
使用def关键字来定义函数
函数名可以是任何有效的Python标识符
函数名后的圆括号内是形式参数列表(简称形参),形式参数列表是调用该函数时传递给它的值,可以有零个、一个或多个,当传递多个参数时各参数之间由逗号分隔。
函数体是函数每次被调用时执行的代码,由一行或多行语句组成。
函数定义阶段:只检测语法不执行代码
定义函数发生的事情:
(1)申请内存空间,把函数体代码存起来
(2)将函数的内存地址绑定函数名
注意:
(1)即使该函数不需要接收任何参数,也必须保留一对空的圆括号。
(2)括号后面的冒号不能省略。
(3)函数体相对于def关键字必须保持一定的空格缩进。
**例如:**定义名为“print_text()”的函数,该函数的功能是输出“Hello world!”
def print_text():
print("Hello world!")
1.2函数的调用
定义了函数后,就相当于有了一段具有特定功能的代码,要想执行这些代码,需要调用函数。
函数调用阶段:才会执行函数体代码
调用函数发生的事情:
(1) 根据函数名函数的内存地址
(2)函数的内存地址()触发函数体代码的运行
函数调用的一般形式为:
例如:
def print_line():
print("************")
def print_text():
print("Hello world!")
print_line() #调用函数
print_line() #调用函数
print_text() #调用函数
print_line() #调用函数
print_line() #调用函数
运行结果:
************
************
Hello world!
************
************
函数调用的三种形式
def foo(x,y):
return x + y
语句形式
foo(1,2)
表达式
res = foo(1,2)
res = foo(1,2) * 10
print(res)
函数的调用可以当做一个参数传给另外一个函数
res = foo(foo(1,2),3)
print(res)
1.3.函数的返回值
函数并非总是直接输出数据,它还可以处理一些数据,并返回一个或一组值。函数返回的值被称为返回值。在Python中,函数使用return语句返回值。
return语句用来退出函数并将程序返回到函数被调用的位置继续执行。
return语句可以同时返回0个、1个或多个结果给函数被调用处的变量。
例:编写函数实现求两数中较小数。
def minimal(x, y): #自定义计算较小值函数
if x > y: #如果x>y成立,返回y的值
return y
else: #否则返回x的值
return x
a = float(input('输入第一个数据:')) #显示提示语并接收a的值
b = float(input('输入第二个数据:')) #显示提示语并接收b的值
c = minimal(a, b) #调用函数,将较小值赋给c
print('较小值为:',c) #输出c的值
运行结果:
输入第一个数据:10
输入第二个数据:5
较小值为: 5.0
进程已结束,退出代码为 0
注意:
如果函数没有return语句,Python将认为该函数以return None结束,即返回空值。
函数也可以用return语句返回多个值,多个值以元组类型保存。
函数体内可以有多个return,但是只要执行一次整个函数就会立即终止并且将其后之当做本次的结果返回
return有三种形式
1、return 值:返回一个值
2、return 值1,值2,值3:返回一个元组
3、没有return、return、return None:默认返回None
2.函数的参数
函数的参数分为两大类
形参: 在函数定义阶段括号内指定的参数(变量名),称之为形式参数,简称形参
实参: 在函数调用阶段括号内指定的参数(变量值),称之为实际参数,简称实参
2.1实参和形参
2.1.1形参
# def foo(x,y):
# # x = 1
# # y = 2
# print(x,y)
#
# foo(1,2)
# 一 位置形参:在函数定义阶段,按照从左到右的顺序依次定义的“变量名”
# 特点:必须被赋值,多一个不行少一个也不行
# def foo(x,y):
# print(x,y)
#
# foo(1,2,3)
# foo(1,)
# 二 默认形参:在函数定义阶段,就已经为某个形参赋值了,该形参称之为默认形参
# 特点:调用阶段可以不用为其赋值
# def foo(x,y=222):
# print(x,y)
# foo(111)
# foo(111,666)
# 注意:
# 1、可以混用位置形参与默认形参,但是默认形参必须放在后面
# def foo(y=22,x): # 错误
# pass
# 2、大多数情况传入的值都应该,就应该将对应的形参定义为默认形参,
# 对于每次传入的值都可能不一样的,就赢将其对应的形参定义为位置形参
# def register(name,age,gender="male"):
# print(name,age,gender)
#
# register("小王",18)
# register("小li",29)
# register("jack",39)
# register("lili",16,'female')
# 3、默认形参的值尽量定义成不可变类型
# # 例1
# m = 100
#
# def foo(x,y=m):
# print(x,y)
#
# m = 200
#
# foo(1)
# 例2
# m = []
#
# def foo(x,y=m):
# print(x,y)
#
# m.append(111)
#
# foo(1)
# 例3
# def register(name, hobby, hobbies=[]):
# hobbies.append(hobby)
# print("%s 的爱好是 %s" % (name, hobbies))
# def register(name, hobby, hobbies=None):
# if hobbies is None:
# hobbies = []
# hobbies.append(hobby)
# print("%s 的爱好是 %s" % (name, hobbies))
#
#
# register('egon',"play")
# register('tom',"read")
# register('lili',"music")
# 五:*args与**kwargs用在形参中:汇总行为
# *用在形参中: *会将溢出的位置实参存成元组然后赋值给紧跟其后的形参名
# def foo(x,*y):
# print(x)
# print(y)
# foo(1,2,3,4,5,6,7)
# foo(1)
# def my_sum(*x): # x = (1,2,3)
# res = 0
# for i in x:
# res += i
#
# print(res)
#
# my_sum(1,2,3)
2.1.2 实参
# 三 位置实参:在函数调用阶段,按照从左到右的顺序依次传入的“变量值”
# 特点:按照顺序传值
# def foo(x,y):
# print(x,y)
#
# foo(1,2)
# foo(2,1)
# 四 关键字实参:在函数调用阶段,按照key=value的形式赋值
# 特点:可以打乱顺序,但是仍然能够为指定的形参赋值
# def foo(x,y):
# print(x,y)
#
# foo(y=2,x=1)
# 注意:
# 可以混用位置实参与关键字实参,但是
# 1、关键字实参必须在后
# 2、不能给同一个形参重复赋值
# def foo(x,y):
# print(x,y)
# foo(1,y=2)
# foo(y=2,1)
# foo(1,2,y=3)
# 六:*与**用在实参中:打撒
# *用在实参中: *会将紧跟其后值打撒成位置实参
# def foo(x,y,z):
# print(x,y,z)
# foo(*[111,222,333]) # foo(111,222,333)
# foo(*"hello") # foo('h','e','l','l','o')
# **用在实参中: **后只能跟字典,**会将紧跟其后字典打撒成关键实参
def foo(x,y,z):
print(x,y,z)
foo(**{'x':111,'y':222,'z':333}) # foo(x=111,z=333,y=222)
2.1.3可变长度的参数(*与**的用法)
# 五:*args与**kwargs用在形参中:汇总行为
# *用在形参中: *会将溢出的位置实参存成元组然后赋值给紧跟其后的形参名
# def foo(x,*y):
# print(x)
# print(y)
# foo(1,2,3,4,5,6,7)
# foo(1)
# def my_sum(*x): # x = (1,2,3)
# res = 0
# for i in x:
# res += i
#
# print(res)
#
# my_sum(1,2,3)
# 六:*与**用在实参中:打撒
# *用在实参中: *会将紧跟其后值打撒成位置实参
# def foo(x,y,z):
# print(x,y,z)
# foo(*[111,222,333]) # foo(111,222,333)
# foo(*"hello") # foo('h','e','l','l','o')
# **用在实参中: **后只能跟字典,**会将紧跟其后字典打撒成关键实参
def foo(x,y,z):
print(x,y,z)
foo(**{'x':111,'y':222,'z':333}) # foo(x=111,z=333,y=222)
3.函数的嵌套
# 函数的嵌套调用:在调用一个函数的过程中,又调用了其他函数
# def max2(x,y):
# if x > y:
# return x
# else:
# return y
#
# def max4(a,b,c,d):
# res1 = max2(a,b)
# res2 = max2(res1,c)
# res3 = max2(res2,d)
# print(res3)
#
# max4(1,2,3,4)
# 函数的嵌套定义: 在函数内又定义了一个函数
# def f1(): # 定义在函数内部的内容有一个效果:函数外无法访问,只有在函数内才可以访问到
# x = 111
# print(x)
#
# f1()
# # print(x)
# def f1():
# def f2():
# print('from f2')
# f2()
#
# f1()
# # f2()
# from math import pi
#
# def circle(radius,mode=0):
# def perimiter(radius):
# return 2 * pi * radius
#
#
# def area(radius):
# return pi * (radius ** 2)
#
# if mode == 0:
# return perimiter(radius)
# elif mode == 1:
# return area(radius)
#
#
# circle(3,0)
4.函数对象
def foo(): # foo->函数的内存地址
print('from foo')
# x = 10 # x->10的内存地址
# 1、可以被赋值
# y = x
# f = foo
# 2、可以当做参数传入
# def f1(func):
# print('====>f1')
# func()
#
# f1(foo) # f1(函数的内存地址)
# 3、可以当做返回值
# def f1(func):
# return func
#
# f = f1(foo)
# print(f)
# 4、可以当做容器类型的元素
# x = 10
# l = [x,foo,foo()]
# # print(l)
#
# l[1]()
def login():
print('登录功能'.center(50, '*'))
def register():
print("注册功能".center(50, '*'))
def transfer():
print("转账功能".center(50, '*'))
def withdraw():
print("提现功能".center(50, '*'))
func_dic = {
"1": ['登录功能', login],
"2": ['注册功能', register],
"3": ['转账功能', transfer],
"4": ['提现功能', withdraw],
}
while True:
print("0 退出")
for k in func_dic:
print(k,func_dic[k][0])
choice = input("请输入命令编号:").strip()
if choice == "0":
break
# if choice == '1':
# login()
# elif choice == '2':
# register()
# elif choice == '3':
# transfer()
# else:
# print("输入的指令错误")
if choice in func_dic:
func_dic[choice][1]()
else:
print("输入的指令错误")
5.名称空间与作用域
5.1.名称空间
名称空间Namespace:存放名字与内存地址绑定关系的地方
5.1.1内置名称空间
存放python解释器自带的名字
python解释器的启动/关闭而产生/回收,因而是第一个被加载的名称空间,用来存放一些内置的名字,比如内建函数名
>>> max
<built-in function max> #built-in内建
5.1.2.全局名称空间
全局名称空间: 存放的是顶级的名字
伴随python文件的开始执行/执行完毕而产生/回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于该名称空间中,如下名字
import sys #模块名sys
x=1 #变量名x
if x == 1:
y=2 #变量名y
def foo(x): #函数名foo
y=1
def bar():
pass
Class Bar: #类名Bar
pass
5.1.3.局部名称空间
局部名称空间:存放的是函数内定义的名字
伴随函数的调用/结束而临时产生/回收,函数的形参、函数内定义的名字都会被存放于该名称空间中
def foo(x):
y=3 #调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中
5.2.名称空间的加载顺序
局部Local-》外层函数Enclosing-》全局Global-》内置Builtin
5.3.作用域
5.3.1全局作用域
全局作用域:全局存活,全局有效
内置名字空间、全局名称空间
5.3.2局部作用域
局部作用域:临时存活,局部有效
局部名称空间
5.4.global和nonlocal关键字
当内部作用域想要使用外部作用域的变量时,可使用global和nonlocal关键字
5.4.1 global关键字
在函数内部修改一个定义在函数外的变量时,须使用global关键字明确声明变量。在函数内部通过global关键字来声明或定义全局变量,可分为两种情况:
(1)一个变量已在函数外定义,如果在函数内需要使用该变量的值或修改该变量的值,并将修改结果反映到函数外,可以在函数内用关键字global明确声明该全局变量。
(2)在函数内部直接使用global关键字将一个变量声明为全局变量,如果在函数外没有定义该全局变量,在调用该函数后,会创建新的全局变量。
def fun():
num += 1
print('函数内num的值为',num)
fun()
print('函数外num的值为',num)
num = 1
def fun():
global num #使用global关键字声明变量为全局变量
num += 1
print('函数内num的值为',num)
fun()
print('函数外num的值为',num)
5.4.2 nonlocal关键字
如果要在一个嵌套的函数中修改嵌套作用域中的变量,则须使用nonlocal关键字
def outer():
num = 1
def inner():
num = 2
print(' inner函数中num的值为',num)
inner()
print(' outer函数中num的值为',num)
outer()
def outer():
num = 1
def inner():
nonlocal num #nonlocal关键字声明
num = 2
print(' inner函数中num的值为',num)
inner()
print(' outer函数中num的值为',num)
outer()
5.5重要结论
(1)局部Local-》外层函数Enclosing-》全局Global-》内置Builtin
(2)名称空间的嵌套关系是在函数定义阶段、扫描语法时就确定好的,与调用位置无关
6.闭包函数
闭函数:定义在函数内部的函数
# def outter():
# def wrapper():
# print('====>wrapper')
包函数: 内部函数引用了一个来自于外层函数的变量
# def outter():
# x = 111
# def wrapper():
# print('====>wrapper',x)