1. 装饰器
装饰器是修改其他函数的功能的函数。
1)前期理解
在python中一切皆对象,函数也是对象。
当你把一对小括号放在后面,这个函数就会执行;然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。举例:
def hi(name="yasoob"):
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
if name == "yasoob":
return greet
else:
return welcome
a = hi()
print(a)
#outputs: <function greet at 0x7f2143c01500>
#上面清晰地展示了`a`现在指向到hi()函数中的greet()函数
#现在试试这个
print(a())
#outputs: now you are in the greet() function
a = hi():a
现在指向到hi()函数中的greet()函数
a():执行greet()函数
当我们写下 a = hi(),hi() 会被执行,而由于 name 参数默认是 yasoob,所以函数 greet 被返回了。如果我们把语句改为 a = hi(name = “ali”),那么 welcome 函数将被返回。我们还可以打印出 hi()(),这会输出 now you are in the greet() function。
2)装饰器模板:
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func) # 重写了我们函数的名字和注释文档(docstring)
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator # 对a_function_requiring_decoration()使用装饰器
def a_function_requiring_decoration():
"""Hey yo! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)相当于@a_new_decorator。装饰之后再调用a_function_requiring_decoration(),效果就是原本的功能+装饰器修改的功能。
from functools import wraps, @wraps(a_func)重写了我们函数的名字和注释文档(docstring)
3)装饰器使用场景
授权(Authorization):
from functools import wraps
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
日志(Logging):
from functools import wraps
def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
# Output: addition_func was called
4)带参数的装饰器
from functools import wraps
# 装饰器外面再套一层
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打开logfile,并写入内容
with open(logfile, 'a') as opened_file:
# 现在将日志打到指定的logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
5)装饰器类
我们现在以一个类而不是一个函数的方式,来重新构建一个装饰器。
还是以logit为例,现在我们有了能用于正式环境的logit装饰器,但当我们的应用的某些部分还比较脆弱时,异常也许是需要更紧急关注的事情。比方说有时你只想打日志到一个文件。而有时你想把引起你注意的问题发送到一个email,同时也保留日志,留个记录。这是一个使用继承的场景。
2. *args, **kargs
常用在装饰器中。
*args 是用来发送一个非键值对的可变数量的参数列表给一个函数.
kwargs 允许你将不定长度的键值对, 作为参数传递给一个函数。 如果你想要在一个函数里处理带名字的参数, 你应该使用kwargs。
#!/usr/bin/env python
def get_sum(*args):
res = 0
for i in args:
res += i
print(res)
lista = [1, 2, 3]
get_sum(*lista)
print('-' * 40)
def get_vk(**kwargs):
for k, v in kwargs.items():
print('k/v : {0} ==> {1}'.format(k, v))
dicta = {'name': 'Test', 'age': 24, 'email': 'test@qq.com'}
get_vk(**dicta)
——————————————————————————
output:
6
----------------------------------------
k/v : name ==> Test
k/v : age ==> 24
k/v : email ==> test@qq.com
def test_args_kwargs(arg1, arg2, arg3):
print(arg1)
print(arg2)
print(arg3)
# 首先使用 *args
args = ("two", 3, 5)
test_args_kwargs(*args)
# 现在使用 **kwargs:
kwargs = {"arg3": 3, "arg2": "two", "arg1": 5}
test_args_kwargs(**kwargs)
在装饰器中使用args的原因:
https://www.cnblogs.com/cmt/p/14580194.html?from=https%3A%2F%2Fwww.cnblogs.com%2Fmarcoxu%2Fp%2F7145304.html&blogId=365485&postId=7145304
https://blog.csdn.net/weixin_45294285/article/details/111085813
3. 调试 Debugging(Python debugger(pdb))
参考:https://docs.python.org/2/library/pdb.html Or https://docs.python.org/3/library/pdb.html
命令列表:
c: 继续执行
w: 显示当前正在执行的代码行的上下文信息
a: 打印当前函数的参数列表
s: 执行当前代码行,并停在第一个能停的地方(相当于单步进入)
n: 继续执行到当前函数的下一行,或者当前行直接返回(单步跳过)
单步跳过(next)和单步进入(step)的区别在于, 单步进入会进入当前行调用的函数内部并停在里面, 而单步跳过会(几乎)全速执行完当前行调用的函数,并停在当前函数的下一行。
4. 生成器 Generators
任意对象,只要定义了next(Python2) 或者__next__方法(next()允许我们获取一个序列的下一个元素),它就是一个迭代器。
可迭代对象就是能提供迭代器的任意对象。Python中任意的对象,只要它定义了可以返回一个迭代器的__iter__方法(iter将根据一个可迭代对象返回一个迭代器对象),或者定义了可以支持下标索引的__getitem__方法,那么它就是一个可迭代对象。
你不想同一时间将所有计算出来的大量结果集分配到内存当中,特别是结果集里还包含循环。生成器也是一种迭代器,但是你只能对其迭代一次。这是因为它们并没有把所有的值存在内存中,而是在运行时生成值。你通过遍历来使用它们,要么用一个**“for”循环**,要么将它们传递给任意可以进行迭代的函数和结构。大多数时候生成器是以函数来实现的。然而,它们并不返回一个值,而是yield(暂且译作“生出”)一个值。这里有个生成器函数的简单例子:
# generator version
def fibon(n):
a = b = 1
for i in range(n):
yield a
a, b = b, a + b
函数使用方法如下:
for x in fibon(1000000):
print(x)
def generator_function():
for i in range(10):
yield i
for item in generator_function():
print(item)
# Output: 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
5. Map, reduce, filter
1)map
Map会将一个函数映射到一个输入列表的所有元素上。不仅用于一列表的输入, 我们甚至可以用于一列表的函数:
格式:
map(function_to_apply, list_of_inputs)
例子:
items = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, items))
不仅用于一列表的输入, 我们甚至可以用于一列表的函数:
def multiply(x):
return (x*x)
def add(x):
return (x+x)
funcs = [multiply, add]
for i in range(5):
value = map(lambda x: x(i), funcs)
print(list(value))
# 译者注:上面print时,加了list转换,是为了python2/3的兼容性
# 在python2中map直接返回列表,但在python3中返回迭代器
# 因此为了兼容python3, 需要list转换一下
# Output:
# [0, 0]
# [1, 2]
# [4, 4]
# [9, 6]
# [16, 8]
2)filter