Python学习之路(五)函数、闭包、匿名函数及装饰器

函数基础

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)# 43是实参
#############函数参数可变参数和不可变参数################

```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)#随机生成 19的整数
ret = random.random()#s生成01之间的小数
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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值