一、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))