函数基础
1、概念
所谓函数,就是把 具有独立功能的代码块 组织为一个小模块,在需要的时候调用
2、定义:
def myfun():
print('我是自定义函数')
myfun()#调用函数
3、函数参数
#############函数传两个参数a,b################
def myfun(a,b):#a和b是形参
'''一般在这里给函数写注释'''
s = a+b
print('%d+%d=%d'%(a,b,s))
myfun(4,3)# 4和3是实参
#############函数参数可变参数和不可变参数################
```cpp
def test(num,num_list):
print('函数内部')
num += num
# 如果参数是可变类型,在函数内部使用了 方法 修改了数据内部
# 那么会影响到函数外部的数据
# num_list.extend([4,5,6])
num_list += num_list # += 就相当于 extend
print(num)
print(num_list)
print('函数执行完成')
gl_num = 10
gl_list = [1,2,3]
test(gl_num,gl_list)
print(gl_num)
print(gl_list)
######################函数缺省参数######################
def print_info(name,gender=True):#缺省参数就是默认参数
gender_text = '男生'
if not gender:
gender_text = '女生'
print("%s 是 %s" %(name,gender_text))
print_info('小明')
print_info('小花',False)
#################缺省参数注意事项#####################
def print_info(name,gender=True,title='学生'):
#使用3对双引号,然后回车
"""
:param name: 姓名
:param gender: 性别
:param title: 职位
:return:
"""
gender_text = '男生'
if not gender:
gender_text = '女生'
print("%s 是 %s,职位是 %s" %(name,gender_text,title))
print_info('小花',False,'学习委员')#如果是按顺序不用 指定参数名
print_info('小明',title='班长') #如果不按顺序传,必须指定参数名
###########################多值参数##########################```
def my_fun(num,*args,**kwargs):
"""
:param num: 实际的参数
:param args: 保存字典类型之外的可变参数
:param kwargs: 保存字典类型的可变参数
:return:
"""
print(num)
print(args)
print(kwargs)
my_fun(1,2,3,[1.2,3],name='小明',age=18)
############多值参数是字典时的拆包################
def my_fun(*args,**kwargs):
"""
:param num: 实际的参数
:param args: 保存字典类型之外的可变参数
:param kwargs: 保存字典类型的可变参数
:return:
"""
print(args)
print(kwargs)
m_list = [1,2,3]
m_dic = {'name':'小明','age':20}
#此时传参数时没有拆包,默认都是列表所以打印结果是:([1, 2, 3], {'name': '小明', 'age': 20}){}
my_fun(m_list,m_dic)
#如果让 函数 识别 m_dic是字典,m_list是列表,参数需要加 *
my_fun(*m_list,**m_dic)
4、函数返回值
#############函数返回值####################
#a和b是形式参数
def myfun(a,b):
'''一般在这里给函数写注释'''
s = a+b
#函数返回值返回的是数据的引用(在内存中的地址),而不是数据本身
return s #函数返回值
#函数的参数传递的是数据的引用(在内存中的地址),而不是数据本身
s = myfun(4,3)
print(s)
##########函数返回值可以是多个,用逗号隔开,接收时一个元组##############
def test(num):
a = 123
b = 'abc'
return a,b;#返回值可以有多个,默认返回一个元组
ret = test(number)#ret是一个元组,我们可以对齐拆包
ret1,ret2 = test(number)
print(ret1)
print(ret2)
5、函数嵌套使用及函数递归
############函数里面调用函数就是函数嵌套##############
def print_lines(char,times):
"""打印一行"""
print(char*times)
def print_rows(char,times,row):
"""打印几行"""
for i in range(row):
print_lines(char,times)
print_rows('-',30,2)
##########函数递归############
#定义:函数里面自己调用自己就是
def digui(num):
print(num)
#递归函数关键点之一,必须设置递归结束的条件,否则死循环直到最后系统抛出异常
if(num == 1):
return #递归关键的之二,函数一层一层的调用,返回值是从最里面一层一层的网外面返回
digui(num-1)
digui(5)
#递归计算求和
def sum_nums(num):
"""
递归计算求和,比如输入参数 10,计算 1+2+3+...10的值
:param num:
:return:
"""
if num == 1:
return 1
temp = sum_nums(num-1)
return temp+num
ret = sum_nums(5)#1+2+3+4+5
print(ret)
执行流程如下所示:
当我们的参数传5的时候一直调用自己,直到传1的时候返回 1.
函数执行的时候是如下: 返回的时候先返回step4的值:
step1:temp = sum_nums(4) step4:返回1,传给step3 的temp
step2:temp = sum_nums(3) step3:返回temp+num=1+2 传给step2 的 temp
step3:temp = sum_nums(2) step2:返回temp+num=1+2+3 传给step1 的temp
step4:temp = sum_nums(1) step1:返回 temp+num=1+2+3+4
最后一个return 是temp+num 也就是 1+2+3+4+5
6、函数模块
在py里面任意一个py文件都可以被认为是一个模块,被另外的py文件引入。在一个py文件里面定义函数以及变量,可以在另外的一个文件里被使用。
file_name = 'This is a test.py '
def print_lines(char,times):
"""打印一行"""
print(char*times)
def print_rows(char,times,row):
"""打印几行"""
for i in range(row):
print_lines(char,times)
在另外的test2.py文件 导入 test.py,然后调用其变量和函数:
import test
print(test.file_name)
test.print_rows('*',10,3)
##########随机数函数模块使用案例####################
import random #直接使用import 导入
ret = random.randint(1,9)#随机生成 1到9的整数
ret = random.random()#s生成0 到1之间的小数
print(ret)
7、局部变量和全局变量
函数外面定义的变量是全局变量
函数内部定义的变量就布局变量
number = 20#全局变量
def test(num):
print('在函数内部num的地址是%d' % id(num));
global number;#函数内部使用global 声明使用全局变量,如果不使用global声明,则此处的number是 局部变量
number = 20+2 #全局变量被修改
return number;
print(number)
ret = test(number)
print(ret)
print(number)
闭包
1、函数引用
def myfun():
print('hello')
print(id(myfun))#函数也有地址,
ret = myfun;#地址赋值给变量,ret 和 myfun是同一个内容
ret();#通过函数引用调用函数
2、闭包
- 闭包定义
在函数内部定义了一个函数,而且内部函数用到了外部函数的局部变量,那么将这个函数以及用到的一些变量称为闭包
def myfun_out(number):
def myfun_in(number_in):
return number_in+number
return myfun_in
ret1 = myfun_out(12)
ret2 = ret1(22)
print(ret2)
- 闭包实例
已知一元方程 ax+b 求
3x+3
3x+5
2x+2
2x+5的值
由于 a和b的值也是可变的,比如3x+3、3x+5和2x+2 和 2x+5 。而x是可变的。所以用闭包实现外层函数传递a和b的值,内层函数传递变量x的值。
def line(a,b):
def inner(x):
return a*x+b
return inner;
ret = line(3,4)
print(ret(2)) #计算3*2+4
- 修改外部函数的局部变量 nonlocal
def count(start=0):
"""
定义计数器
:param start:计数的起始值
:return:
"""
start = start
def inner(diff,count):#number 计数的步进值、count 计数的次数
nonlocal start #nonlocal 声明之后 内部函数就可以修改外部函数的局部变量 start了
while(count):
start += diff
count -= 1
return start
return inner
匿名函数
- 简单定义
lambda 参数列表 :return [表达式] 变量
ret = lambda x,y:x+y
print(ret(3,4))
- 应用1
infos = [
{'name':'wang','age':20},
{'name':'li','age':30},
{'name':'zhao','age':25}
]
# 给列表排序,按照字典里面age的值排序
infos.sort(key = lambda a:a['age'])
print(infos)
- 应用2:当函数参数是函数时,可以用匿名函数
def demo(a,b,func):
ret = func(a,b)
return ret
ret = demo(5,10,lambda x,y:x+y)
print(ret)
模块(任何一个py文件都可以看成一个模块)
- 模块导入1.0-----
import 模块1
import 模块2
然后就可以使用 模块1或模块2里面的全局变量和函数了
- 模块导入2.0
在被导入模块里面 使用 name == "main"表示此段代码只在 当前环境下才执行。如下,我们在test模块下使用:
file_name = 'This is a test.py '
def print_lines(char,times):
"""打印一行"""
print(char*times)
def print_rows(char,times,row):
"""打印几行"""
for i in range(row):
print_lines(char,times)
if __name__ == "__main__":##代表只在 当前文件下才执行下面代码
print_rows('#',10,5)
包(包含多个模块的特殊目录)
新建时,新建 Python Package ,就是新建一个包。当目录里面有一个__init__.py文件,此时就是一个包
命名规则和变量命名规则一样
当我们一个文件里面使用到多个模块时,我们就可以把这些个模块放在一个包里面,使用时只要引入这个包即可。导入方式
装饰器
装饰器的功能在不修改原来函数的基础上,给此函数新增功能
- 认识装饰器----只装饰一次
def check(func):
print('操作之前需要先验证')
def inner():
print('业务部门.....')
func()
return inner
@check #这样操作相当于 fun1 = check(fun1)
#写好的功能模块
def fun1():
print('已经写好的业务部门做的相关操作')
fun1()#最后执行 fun1 其实是执行的 check里面的 inner 函数
输出结果如下:
---操作之前需要先验证
---业务部门.....
---已经写好的业务部门做的相关操作
- 再识装饰器 多次装饰
解析器是从上往下执行,
装饰器是从下往上装饰
def makeBlod(fn):
def wrapper():
return "<b>" + fn() + "</b>"
return wrapper
def makeItalic(fn):
def wrapper():
return "<i>" + fn() + "</i>"
return wrapper
@makeBlod #后装饰个地方:demo1 = makeBlod(demo1)
@makeItalic #按照规则先装饰这个地方,后装饰上面部分。demo1 = makeItalic(demo1)
def demo1():
return 'hello world-3'
print(demo1())
输出结果是:<b><i>hello world-3</i></b>
进一步理解双层装饰器
def makeBlod(fn):
print('Blod外层函数')
def wrapper():
print('Blod内层函数')
return "<b>" + fn() + "</b>"
return wrapper
def makeItalic(fn):
print('Italic外层函数')
def wrapper():
print('Italic内层函数')
return "<i>" + fn() + "</i>"
return wrapper
@makeBlod
@makeItalic
def demo1():
print('demo1执行')
return 'hello world-3'
print(demo1())
打印结果:
Italic外层函数
Blod外层函数
Blod内层函数
Italic内层函数
demo1执行
<b><i>hello world-3</i></b>
由打印结果可知,确实是由下到上执行,但是返回时像递归一样从内到外的返回
- 被装饰的函数带参数
def myfun(func):
def wrapper(a,b):
print(a,b)
func(a,b)
return wrapper
@myfun
def sum(a,b):#被装饰的函数,带两个参数
print(a+b)
sum(2,3)
- 装饰器中的return
def myfun():
def wrapper(func):
print('%s 被调用了' %(func.__name__))
return func() #由于被装饰的函数demo有了返回值,所以想要得到此处也要返回
return wrapper
@myfun
def demo():# 被装饰的函数有返回值
print('在demo里面')
return 'hello Python'
print(demo())
- 装饰器带参数(外层函数带参数)
def myfun(pre='Hello'):
def wrapper(func):
print('%s 被调用了' %(func.__name__))
print(pre)
return func
return wrapper
@myfun('Python')
def demo():
print('I am demo')
demo()