函数装饰器和闭包<python>

一、python如何计算装饰器语法

二、python如何判断变量是不是局部的

三、闭包存在的原因和工作原理

四、nonlocal能解决什么问题

变量作用域规则

b=6
def f2(a):
    print(a)
    print(b)
    b=9
f2(3)

报错的原因:python不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量。

闭包

闭包是指延申了作用域的函数,其中包含函数定义体中引用、但是不在定义体中定义的非全局变量,可以访问定义体之外定义的非全局变量。

示例:累计求平均值

类实现
class Average:
    def __init__(self):
        self.datalist=[]

    def __call__(self, num):
        self.datalist.append(num)
        avg=sum(self.datalist)/len(self.datalist)
        return avg
通过闭包实现
def average():
    datalist=[]
    def inner(num):
        datalist.append(num)
        avg=sum(datalist)/len(datalist)
        return avg
    return inner

avg=average()

上一个的效率不高

def average():
    total=0
    count=0
    def inner(num):
        nonlocal total,count
        count+=1
        total+=num
        return total/count
    return inner

avg=average()

装饰器基础知识

简单装饰器

装饰器是可调用的对象,其参数是另一个函数。装饰器可能会处理被装饰的函数,然后将其返回,或者将其替换成另一个函数或可调用对象。

def deco(func):
    def warpper():
        func()
    return warpper

@deco
def target():
    print('target.......')


target()
#@deco进行的操作如下
#target=deco(target)
#target()

装饰器两大特性:能把被装饰的函数替换成其他函数,装饰器在加载模块时立即执行。

data=[]
def register(func):
    print(f'running register{func}')
    data.append(func)
    return func

@register
def f1():
    print('running f1...')

@register
def f2():
    print('running f2...')

def f3():
    print('running f3...')

def main():
    print('running main...')
    print('data-->',data)
    f1()
    f2()
    f3()

if __name__ == '__main__':
    main()

叠放装饰器

def d1(func):
    def inner():
        print('d1')
        func()
    return inner

def d2(func):
    def inner():
        print('d2')
        func()
    return inner

@d2
@d1
def fuc():
    print('fuc...')

fuc()

参数化装饰器

import time

from functools import wraps
li=[9,8,74,23,35,154,13,54,12,4]

def test(*args):
    def sortEasy(fn):
        @wraps(fn)
        def print_easy(*args,**kwargs):
            print('排序前', li)
            fn(*args, **kwargs)
            print('排序后', li)
        @wraps(fn)
        def count_time(*args,**kwargs):
            t1=time.time()
            fn(*args,**kwargs)
            t2=time.time()
            print(t2-t1)
        if len(args)==0:
            return print_easy
        else:
            return count_time
    return sortEasy


@test(1)
def bubble_sort(li):
    for i in range(len(li)-1):
        ischanged=True
        for j in range(len(li)-i-1):
            if j+1<=len(li) and li[j]>li[j+1]:
                li[j],li[j+1]=li[j+1],li[j]
                ischanged=False
        if ischanged:
            return

bubble_sort(li)

内置装饰器@lru_cache

from functools import lru_cache
import sys
sys.setrecursionlimit(10000000)
@lru_cache(maxsize=1111111111)#动态规划
def fibonacci(n):
    if n<2:
        return n
    return fibonacci(n-1)+fibonacci(n-2)

可以把耗时的函数结果保存起来

在类中的装饰器<描述符>

@classmethod        类方法
@staticmethod       静态方法 

@property           特性

装饰器在测试中的应用

1、parameterized

import csv
import time
import unittest

from selenium import webdriver
from parameterized import parameterized


with open('test.csv','r') as f:
    data=csv.reader(f)
    data=list(data)[0]
driver=None

def setUpModule():
    global driver
    driver=webdriver.Chrome()
    driver.maximize_window()


class Test(unittest.TestCase):

    def setUp(self) -> None:
        driver.get('https://www.baidu.com/')

    @parameterized.expand(
        [(i,) for i in data]
    )
    def test(self,search):
        time.sleep(1)
        driver.find_element_by_id('kw').send_keys(search)
        driver.find_element_by_id('su').click()

    def tearDown(self) -> None:
        time.sleep(2)
        
    @classmethod
    def tearDownClass(cls) -> None:
        driver.quit()

2、解决try...expect问题

3、生成测试报告

题外话:----------------------------------------------------

继承

推出继承的初衷是让新手顺利使用只有专家才能设计出来的框架。

                                                                                                ---------Alan Kay

class Base:
    def __init__(self):
        print('Base.__init__')

class A(Base):
    def __init__(self):
        Base.__init__(self)
        print('A.__init__')

class B(Base):
    def __init__(self):
        Base.__init__(self)
        print('B.__init__')

class C(A,B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)
        print('C.__init__')
C()

super

class Base:
    def __init__(self):
        print('Base.__init__')

class A(Base):
    def __init__(self):
        super().__init__()
        print('A.__init__')

class B(Base):
    def __init__(self):
        super().__init__()
        print('B.__init__')

class C(A,B):
    def __init__(self):
        super().__init__()
        print('C.__init__')
C()

fixture for unittest

import unittest

def setUpModule():
    print('setUpModule')
def tearDownModule():
    print('tearDownModule')

class Test(unittest.TestCase):

    def setUp(self) -> None:
        print('setUp')

    @classmethod
    def setUpClass(cls) -> None:
        print('setUpClass')


    def tearDown(self) -> None:
        print('tearDown')

    @classmethod
    def tearDownClass(cls) -> None:
        print('tearDownClass')

    def test(self):
        print('test')

对装饰器进行解包装

需要访问未经包装过的原函数

import functools

def deco(func):
    @functools.wraps(func)
    def inner(x,y):
        print(x,y)
        return func(x,y)
    return inner

@deco
def add(x,y):
    return x+y

add1=add.__wrapped__
print(add1(2, 3))

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值