python基础(09闭包&装饰器)

python系列文章目录

python基础(01变量&数据类型&运算符)
python基础(02序列共性)
python基础(03列表和元组)
python基础(04字符串&字典)
python基础(05集合set)
python基础(06控制语句)
python基础(07函数)
python基础(08类和对象)


文章目录

  • python系列文章目录
  • 前言
  • 一、函数的特性
  • 二、闭包
    • 1.定义
    • 2.闭包条件
    • 3.闭包使用
    • 4.闭包特殊用途
  • 三、装饰器
    • 1.定义
    • 2.单个装饰器调用
    • 3.多个装饰器调用
    • 4.带参数的装饰器
    • 5.闭包可实现函数前或者后添加新功能
  • 总结


前言

本文主要介绍了函数的特性、闭包以及装饰器的用法,如果理解有困难,多敲几遍也就悟了。


一、函数的特性

1.函数可以作为变量,赋值给另外一个变量

def add(x):
    return x+1
a = add    #a指向add函数的地址
print(a)   #
print(a(5))# 6
print(add(5))# 6

2.函数可以作为参数传入

def execute(f):
    return f(5)
print(execute(add))     #6,相当于add(5)

3.函数对象可以作为返回值

def add(x):
    return x+1

def get_add():
    return add
c  = get_add()  #将get_add()的返回值给c了,返回值为add,相当于c=add

print(c)  #
print(c(5)) #6

4.嵌套函数里面 调用外层函数时,运行到内层的def语句 仅仅是完成对内层函数的定义,而不会去调用内层函数

x = 99
def f1():
    x = 88
    def f2():
        print(x)

f1() #空

5.局部作用域在函数结束之后会立即消失,但是enclosing 作用域在嵌套函数返回后 仍然有效

x = 99
def f1():
    x = 88
    def f2():
        print(x)
    return f2

action = f1()
action() #88

二、闭包

1.定义

  • 就是一个函数
  • 在一个内部函数里,存在对外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就认为是闭包,外部函数被认为是闭包函数

2.闭包条件

  • 嵌套函数:外部函数、内部函数
  • 内部函数中要使用外部函数的变量
  • 外部函数必须还有返回值,返回内部函数名
def out():
    x=1
    def inner():
        print(f"x={x}")
    inner()  #属于闭包函数

--------------------------------->>>>

def out(x):
    def inner():
        print(f"x={x}")
    inner() #属于闭包函数,参数也属于局部变量

3.闭包使用

例子:求两个数字的和

常规写法

 def sum(a,b)
    return a+b

闭包写法

def funOut(num1):
    def funIn(num2):
        #内部函数修改外部函数的变量
        nonlocal num1
        num1+=100
        return num2+num1
    return funIn
f=funOut(100)
print(f)   #打印的是funIn的地址  返回值是funIn
ret=f(200)
print(ret)  #300

4.闭包特殊用途

  • 在不改变源代码的前提下,进行添加修改
  • 例子:调用函数时添加一个日志功能
def writeLog(func):
    print("访问了方法名:",func.__name__,"\t时间:",time.asctime())


def funcOut(func):
    def funcIn():
        writeLog(func)  #在函数前加功能 后面也可以加功能
        func()
    return funcIn


def fun1():
    print('jiajia')


fun1=funcOut(fun1)
fun1()
------------------------------>>
访问了方法名: fun1 	时间: Sun Aug 25 13:59:00 2024
jiajia

三、装饰器

1.定义

就是一种闭包,使闭包的访问形式更方便

def w1(func):
    def inner():
        #验证1
        #验证2
        func()
    return inner()


------------------------------------------------------------------->>>
调用w1函数,同时把f1传进去,返回inner函数-----调用inner(),验证之后,执行f1()
经过w1装饰的f1,指向了inner函数地址,效果等同于f1()=w1(f1)
------------------------------------------------------------------->>>
d
@w1        
def f1():
    
    print('f1')

2.单个装饰器调用

例子:调用时添加日志信息

第一步:添加的新功能编写

#写一个输出日志功能
import time
def writeLog(func):
    #添加一个异常判断
    try:
        file=open("log,txt",'b',encoding='utf-8')
        file.write("访问:")
        file.write(func.__name__)  #获取函数的名字
        file.write("\t")
        file.write("时间:")        #获取时间
        file.write(time.asctime())
        file.write("\t")
    except Exception as e:
        print(e.args)
    finally:
        file.clos() #释放资源

第二步:写一个闭包

def funcOut(func):
    def funcIn():
        writeLog(func) #内部函数引用外部函数
        func()
    return funcIn

第三步:装饰器调用

@funcOut  #相当于fun1=funcOut(fun1)
def fun1():
    print("功能1")
@funcOut
def fun2():
    print("功能2")

3.多个装饰器调用

例子:给foo函数新增2个功能,两个装饰器实现

第一步:编写新功能

print("i am foo")#比较简单可省略 直接写到闭包里

print("hello")#比较简单可省略 直接写到闭包里

第二步:写2个闭包

def funOut1(func):
    def funIn():
        print("i am foo")   #调用函数前,加的新功能1
        func()
    return funIn

------------------------------------------------
def funOut2(func):
    def funIn():
        print("hello")   #调用函数前,加的新功能2
        func()
    return funIn

第三步:装饰器调用

@funOut2      #hello  先调用
@funOut1      #i am foo  后调用
def foo():
    print("这是foo的原本功能")
foo()
------------------------------------------>>

hello
i am foo
这是foo的原本功能

4.带参数的装饰器

(1)、带同等数量的参数

注意:内部函数也要同步定义同等数量的参数 才能确保装饰器调用不出错

例子:打印函数的名称和时间

第一步:添加新功能

import time
def writeLog(func):
    print("访问了方法名:",func.__name__,"\t时间:",time.asctime())

第二步:编写装饰器

def funOut(func):
    def funIn(a,b):
        writeLog(func)
        return func(a,b)
    return funIn

第三步:装饰器调用

@funOut
def sum(a,b):
    return a+b
s=sum(10,15)
print(s)

解释

  • 原函数有两个参数:a、b
  • 所以给装饰器的内部函数以及返回值需要加上同样的参数
  • 数量要相等

(2)、通用装饰器

  • 注意:通用装饰器:*args,**kwargs
  • 元组 字典 接收多个值 多个字典

例子:返回一个函数的名称和时间

import time
def funcOut(func):
    def funcIn(*args,**kwargs):
        writeLog(func)
        return func(*args,**kwargs)
    return funcIn

    
def writeLog(func):
    print("访问了方法名:",func.__name__,"\t时间:",time.asctime())

    
@funcOut
def sum(a,b,c):
    return a+b+c
s=sum(1,2,3)
print(s)

(3)、装饰器本身带有参数

注意:它就是一个函数 会被立即执行 返回结果是一个装饰器

第一步:新功能(省略)
第二步:装饰器

import time
import random
def loglever(level):
    def w(func):
        def inner(a, b):
            start_time = time.time()
            func(a, b)
            end_time = time.time()
            print(f"运行时间为{end_time - start_time}")
            if level == "INFO":
                print("it's info level")
        return  inner
    return w #返回值w是装饰器

第三步:调用

@loglever("INFO")
def add_demo(a,b):
    time.sleep(random.randrange(1, 5))
    print(a+b)

解释:

  • 在装饰器的外层又套用了一层函数
  • 每一层函数都要返回其内部函数

5.闭包可实现函数前或者后添加新功能

问题:给一个函数添加一个功能,计算这个函数的运行时间为多少?

1.不使用装饰器实现

import time
import random

def time_demo():
    start_time=time.time()
    time.sleep(random.randrange(1,5))
    print("welcome to xx")
    end_time=time.time()
    print(f"运行时间为{end_time-start_time}")

time_demo()

2.装饰器实现

第一步:编写新功能(省略)

第二步:编写装饰器

def funout(fun):
    def inner():
        start_time = time.time()
        fun()
        end_time = time.time()
        print(f"运行时间为{end_time - start_time}")

    return inner

第三步:装饰器调用

@funout
def time_demo():
    time.sleep(random.randrange(1,5))
    print("welcome to xx")

time_demo()

总结

本文先介绍了函数的一些特性,详细的介绍了闭包、闭包的条件使用,以上两个主要为装饰器做铺垫,最后详细的介绍了装饰器的用法。如果理解起来有难度,多敲几遍,就能get到用法。

你可能感兴趣的:(python基础,python,功能测试,自动化,开发语言)