生活当中有许多一些重复且有规律的事情,比如计算圆的面积:S=πr2,这时公式是固定的,我们来看一段代码:
#计算3个圆的面积
r1 = 11.3
r2 = 5.6
r3 = 9.4
s1 = 3.14*r1*r1
s2 = 3.14*r2*r2
s3 = 3.14*r3*r3
如果有一千个圆,一万个圆呢?难道这样去写一千次一万计算吗?这个时候就要用到函数了,函数是一个实现特定功能的代码模块。
'''
计算圆的面积
'''
def get_area_of_circle(r):
print('circle\'s area:',3.14*r*r)
我准备了一些爬虫案例,还有一些小游戏源码,你们自取:
在python中,函数分为两种,一种是内置函数,一种是自定义函数:
内置函数:python解释器内定义完成,调用即可。如:print(),int()等
自定义函数:自己根据特定功能定义的函数
无参函数
#无参函数
def welcome():
print('欢迎来到python世界!')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JFoUBDJp-1650009117985)(C:\Users\图灵python学院\Desktop\课件\1,python\images\6\6-1.png)]
有参函数
无参函数内部代码功能比较固定,当函数需要更加灵活的配置时候,可以定义有参函数来解决问题。
形参与实参
形参:在函数定义阶段定义的参数为形参,声明传入变量的含义,等于变量名
实参:在调用函数阶段传入的值,等于变量的值
在定义阶段,形参跟实参没有任何关系。调用时,实参会绑定复制给形参,且在函数体内生效。函数调用结束后接触绑定关系。
位置参数
从左到右按顺序定义的参数叫位置参数,实参的传值必须跟形参一一对应。
#位置参数
def show_info(name,age):
print('my name is %s,i\'m %s years old!'%(name,age))
#函数调用
show_info('张三',18)
关键字参数
除了位置参数以外,也可以按照key-value形式传值。
位置参数可以跟关键字参数混用,但是注意两点:1,位置参数必须在关键字参数之前 2,不能为同一个形参重复传值
#关键字传参
show_info(name='张三',age=18)
#混合传参
show_info('李四',age=18)
默认参数
默认形参:在定义函数阶段就对形参进行赋值,调用时可以不赋值
注意:默认形参推荐使用不可变类型!
#默认形参
def show_info(name,age,country='中国'):
print('我叫%s,我今年%s岁,我的祖国是%s!'%(name,age,country))
show_info('张三',18)
#结果
我叫张三,我今年18岁,我的祖国是中国!
可变长参数
当函数在调用时不确定传入的实参个数时,就可以使用可变长参数来定义形参。
函数在调用时有位置参数与关键字参数两种形式,因此可变长参数也分别提供了对应的解决方案。
*args:溢出的关键字以元组的形式保存,用于接受溢出的位置实参
#可变长参数
#需求:定义一个求和的函数,但是传入的数字个数不确定
#格式:*args 星号后可跟任意名字,约定俗成为args,溢出实参以元组形式保存赋值
def count_num(*args):
res = 0
#迭代元组元素并相加
for item in args:
res+=item
print('和为:%s'%res)
count_num(1,2,3,4,5)
实参在传值时也能使用*,*后的值会被拆分成对应的位置实参
#实参带*
def print_num(x,y,z):
print(x,y,z)
print_num(*[1,23])
形参实参都使用*
#形参实参都带*
def print_num(x,y,*args):
print(x,y,args)
print_num(1,2,3,4,5,6)
print_num(1,2,*[3,4,5,6])
**kwargs:溢出的关键字以字典的形式保存,用于接受溢出的关键字实参
#**kwargs 接收溢出的关键字实参
#接收学员信息的函数
def student_info(name,age,**kwargs):
print(name,age,kwargs)
student_info('张三',18,gender=3,country='chinese')
#实参使用**
student_info(**{'name':'李四','age':18,'gender':6,'country':'chinese'})
混用*与**,*args必须在**kwargs之前
#能够接收任意函数
def func(*args,**kwargs):
print(args,kwargs)
func(1,2,3,4,name='王五',gender=6)
函数返回值
在调用函数需要结果时,可以使用return关键字返回运算结果
#return 返回函数运算结果
def count_num(*args):
res = 0
#迭代元组元素并相加
for item in args:
res+=item
#返回运算结果
return res
#接收函数返回值
num = count_num(1,2,3,4,5)
如果需要声明一个函数,但是留待后续开发,可以使用关键字pass
#pass关键字 声明空函数
def func(name,age):
pass
命名空间与作用域
A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries
程序内部的代码生效范围有层级,层级范围叫做命名空间,不同空间内的变量生效范围大小不一
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K08RikID-1650009117987)(C:\Users\图灵python学院\Desktop\课件\1,python\images\6\6-2.png)]
内置命名空间
范围最大,python解释器启动时产生,关闭时销毁。内置函数与异常都属于这个范围,如print,input等,任何模块都可访问它,
#内置名称空间 <built-in function print>
print(print)
全局命名空间
模块的全局命名空间在模块定义被读入时创建;通常,模块命名空间也会持续到解释器退出。 模块内所有代码(类,函数,变量,常量)与其它模块内导入所有代码都属于这个范围
局部命名空间
一个函数的局部命名空间在这个函数被调用时创建,并在函数返回或抛出一个不在函数内部处理的错误时被删除。每次递归调用都会有它自己的本地命名空间。
当程序去寻找一个变量 x 时,它的寻找顺序如下:
1,局部命名空间:当前函数或类的方法内,如果找到该变量则停止搜索
2,全局命名空间:当前模块内,如果找到了名字为x的类,函数,变量则停止搜索
3,内置命名空间:如果上述都没有找到,则会在内置函数或变量寻找
4,以上都没找到则会报错: NameError: name ‘xx’ is not defined。
#命名空间1
x = 1
def func1():
print(x)
def func2():
x = 2
print(x)
func1()
func1()
func2()
#命名空间2
input=111
def func3():
input = 222
print(input)
func3()
#命名空间3
x = 111
def func4():
print(x)
x = 222
func4()
global与nonlocal关键字
locals():查看所有局部命名空间
globals():查看所有全局命名空间
global:在函数内声明该变量为全局对应变量
nonlocal:修改函数外层函数内对应变量
#global关键字
x = 111
def func():
global x
x = 222
print(x)
func()
#nonlocal关键字
x = 111
def func1():
x = 222
def func2():
nonlocal x
x = 333
print('func2的x:',x)
func2()
print('func1的x:',x)
func1()
函数的引用
函数的引用本质是一个存储函数地址的变量,同样也可以对它做变量相同的操作。
'''
@AUTHOR:小帅
@FILE:2_函数引用操作.py
@DATE:2022/2/18
'''
#函数引用赋值
def func1():
print('hello world!')
f = func1
print(f,func1)
func1()
#函数引用传参
def func2(func):
print(func)
func2(func1)
#函数引用作为容器元素
def func3():
print('i\'m func3!')
def func4():
print('i\'m func4!')
def func5():
print('i\'m func5!')
func_dict = {'f3':func3,'f4':func4,'f5':func5}
#调用
func_dict['f3']()
闭包函数
**闭包:在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。**
闭指内部函数是封闭的,定义好以后外部不能直接访问与修改。包则指的是包裹内部函数的外部函数。
注意: 返回闭包中不要引用任何循环变量,或者后续会发生变化的变量。
#闭包函数
#外部函数
def outer():
#局部变量
name = '张三'
#内部函数
def inner():
print(name)
#返回内部函数地址
return inner
#闭包错误使用
def func1(*args):
ls = []
for i in range(0,4):
def func2():
return i*i
ls.append(func2)
return ls
func3 = func1()
print(func3[0]())
print(func3[1]())
print(func3[2]())
装饰器
装饰器就是用于拓展原有函数功能的一种函数,在不修改原有函数代码的前提上给原有函数加上新的功能。
开闭原则:对功能拓展部分是开放的,对源代码的修改是封闭的
'''
@AUTHOR:小帅
@FILE:3_装饰器.py
@DATE:2022/2/18
'''
import time
#计算数字之和
def count(num):
res = 0
for i in range(0,num+1):
res+=i
print(res)
#需求:给上述函数加上计算函数运行功能
#思考:如何去设计一种合理方便的方式
def decorator(func):
#内部函数添加功能
def wrapper(*args,**kwargs):
start = time.time()
#调用传入函数
func(*args,**kwargs)
#睡眠3秒,模拟执行时间
time.sleep(3)
end = time.time()
print('执行时间:',(end-start))
return wrapper
# count = decorator(count)
# count(100)
#语法糖调用方式
@decorator
def show():
print('hello world!')
show()
有参装饰器
#需要对用户实名制进行验证
def check_name(bool):
def deco(func):
def wrapper(*args,**kwargs):
if bool==True:
print('您已经实名制,可以发言!')
res = func(*args,**kwargs)
return res
else:
print('您没有实名制,不能评论!')
return wrapper
return deco
#评论函数
@check_name(False)
def comments():
comm = input('请输入您的评论:')
print(comm)
comments()