接下来的文章学习Python的高级内容,这部分和之前相比有一定的难度,需要认真学习。加油吧,少年!
两个魔法变量 在Python中有两个变量参数容易困扰我们。它们是*args和**kwargs。接下来我们看看究竟是什么意思!
*args*args和**kwargs主要用于函数定义。可以将不定数量的参数传递给函数。*args是用来发送一个非键值对的可变数量的参数列表给函数。
举个🌰:
1 2 3 4 5 6 7 def test_var_args(f_arg, *argv): print('first normal arg: ', f_arg) for arg in argv: print('anothor arg throgh * argv:', arg) test_var_args('yasoob', 'python', 'eggs', 'test')
输出结果:
1 2 3 4 first normal arg: yasoob anothor arg throgh * argv: python anothor arg throgh * argv: eggs anothor arg throgh * argv: test
输出结果看出: f_arg只对应一项。
**kwargs**kwargs允许将不定长度的键值对,作为参数传递。
🌰:
1 2 3 4 5 6 def greet_me(**kwargs): for key, value in kwargs.items(): print("{0} == {1}".format(key, value)) greet_me(name = "yasoob", age = "12")
输出结果:
1 2 name == yasoob age == 12
*args和**kwargs使用使用它们调用函数,🌰:
1 2 3 4 5 6 7 8 9 10 11 12 13 def test_args_kwars(arg1, arg2, arg3): print('arg1', arg1) print('arg2', arg2) print('arg3', arg3) # 使用*args args = ('two', 3, 5) test_args_kwars(*args) # 使用**kwargs kwargs = {'arg3': 3, 'arg2': 'two', 'arg1': 5} test_args_kwars(**kwargs)
标准参数与*args、**kwargs在使用时的顺序。
some_func(frags, *args, **kwargs)
调试(Debug) 调试在处理代码bug非常重要。
从命令行运行
触发调试功能,第一行指令处停止。
从脚本内部运行 设置断点,使用pdb.set_trace()方法实现。
1 2 3 4 5 6 7 import pdb def make_bread(): pdb.set_trace() return "I dont have time" print(make_bread())
命令列表
c: 继续执行
w: 显示当前正在执行的代码行的上下文信息
a: 打印当前函数的参数列表
s: 执行当前代码行,并停在第一个能停的地方(相当于单步进入)
n: 继续执行到当前函数的下一行,或者当前行直接返回(单步跳过)
n 和 s 区别: s单步进入会进入当前行调用函数内部并停在里面,而单步跳过会全速执行完当前行调用的函数,并停在当前函数的下一行。
其他内容请参考官方文档
生成器 前面在学习类时,简单学习了生成器。接下我们将深入学习生成器相关知识。学习生成器之前,我们需要了解迭代器和相关内容。
迭代器是让程序可以迭代遍历一个容器的对象。分为三个部分:
可迭代对象(iterable)
迭代器(iterator)
迭代(iteration)
可迭代对象(iterable) Python中任意对象,只要它定义了可以返回一个迭代器的__iter__方法,或者定义了可以支持下索引的__getitem__方法,那么他就是一个可迭代对象。简单来说,就是提供了迭代器的对象。
迭代器(iterator) 对象只要实现__next__方法,它就是一个迭代器。
迭代(iteration) 例如,循环遍历就是迭代。
生成器 生成器也是一种迭代器,但是只能对其迭代一次。因为它们并没有把所有的值存在内存中,而是运行时生成值。通过遍历来使用它。另外,它们并不返回值,而是yield一个值。
举个🌰
1 2 3 4 5 6 7 8 def generator_function(): for i in range(10): yield i for item in generator_function(): print(item) # 输出 0 - 9
上面的只是例子。真正的运行场景是:不想在同一时间创建大量结果集分配到内存中,减少资源消耗。在Python3中生成器应用很广广泛。
高级函数 Map, Fiter和Reduce三个函数为函数式编程提供便利。
Map Map将一个函数映射到一个输入列表的所有元素上。
格式:
将列表中元素一个个传递给函数,并收集输出。在Python3中返回的是迭代器。 通常,使用匿名函数来配合map。
例如:
1 squared = list(map(lambda x: x ** 2, range(1, 10)))
Filter 顾名思义,Filter过滤列表中的元素,并且返回一个所有符合要求的元素组成的列表。符合要求就是函数映射到该元素时返回值为True。
1 2 3 4 5 6 number_list = range(-5, 5) less_than_zero = filter(lambda x : x < 0, number_list) print(list(less_than_zero)) # Output: [-5, -4, -3, -2, -1]
Reduce 对一个列表进行一些计算并返回结果时, Reduce是非常有用的函数。
例如:计算乘积
1 2 3 4 5 from functools import reduce product = reduce((lambda x, y: x * y), [1, 2, 3, 4]) print(product) # output: 24
装饰器 装饰器(Decorators)是Python的一个重要部分。他们是修改其他函数的功能的函数。
学习装饰器之前,你应该知道一切皆对象、函数定义函数、函数返回函数、将函数作为参数传递。如果对上面内容不了解,那请补一下面向对象吧。
第一个装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 def a_new_decorator(a_func): def wrapTheFunction(): print("before") a_func() # 注意有括号,别问我怎么知道的 print("after") return wrapTheFunction def a_function_requiring_decoration(): print("dslafalsfdsa") a_function_requiring_decoration() # Output: dslafalsfdsa a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) # 获得返回函数 a_function_requiring_decoration() # Output:before # dslafalsfdsa # after
装饰器作用:封装了一个函数,用来修改函数行为
上面的简短写法:
1 2 3 4 5 6 7 8 @a_new_decorator def a_function_requiring_decoration(): print("dslafalsfdsa") a_function_requiring_decoration() # Output:before # dslafalsfdsa # after
上面的@a_new_decorator就相当于a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)。
👆是装饰器的基本工作原理。但是这样写存在一个问题。
请看:
1 2 3 print(a_function_requiring_decoration.__name__) # Output : wrapTheFunction
我们希望的结果是,Output应该输出:a_function_requiring_decoration。Python提供了一个函数解决这个问题,就是functools.wraps。
修改方法:
1 2 3 4 5 6 7 8 def a_new_decorator(a_func): @wraps(a_func) def wrapTheFunction(): print("before") a_func() # 注意有括号,别问我怎么知道的 print("after") return wrapTheFunction
在wrapTheFunction之前添加@wraps()。注意需要引包from functools import wraps。
好了现在学会装饰器了,接下来练习一下吧!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from functools import wraps def decorator_name(f): @wraps(f) def decorated(*args, **kwargs): if not can_run: return "Function will not run" return f(*args, **kwargs) return decorated @decorator_name def func(): return "Function is running" can_run = True print(func()) can_run = False print(func()) # Output: # Function is running # Function will not run
@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性
使用场景 授权检验
装饰能有助于检查某个人是否被授权使用一个web应用的断点。它们被大量使用在Flask和Django框架中。
日志
日志是装饰器运行的另一个亮点。
带参数的装饰 @wraps可以接收一个参数,就像普通的函数一样。我们也可以实现。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from functools import wraps # 定义一个函数,返回装饰器 def logit(logfile = 'out.log'): # 定义一个装饰器 def logging_decorator(func): # 使用wraps重新设置“__name__” @wraps(func) def wraped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) with open(logfile, 'a') as opened_file: opened_file.write(log_string + '\n') return func(*args, **kwargs) return wraped_function return logging_decorator @logit() def myfunc1(): pass myfunc1() # output : myfunc1 was called # 设置文件名称 @logit(logfile = 'func2.log') def myfunc2(): pass myfunc2() # output : myfunc2 was called
装饰器类 上面只是将装饰器写成函数的形式,接下来,以类的形式实现装饰器。
下面还是以logit为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from functools import wraps class logit(object): def __init__(self, logfile = 'classout.log'): self.logfile = logfile def __call__(self, func): @wraps(func) def wrapped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) # 打开并写入日志 with open(self.logfile, 'a') as opened_file: # 将日志保存到指定文件 opened_file.write(log_string + '\n') # 发送一个通知 self.notify() return func(*args, **kwargs) return wrapped_function def notify(self): # 只打印日志,不做别的 pass
调用方法和函数形式相同。
因为是装饰器类,所以具有类的特性:
1 2 3 4 5 6 7 class email_logit(logit): def __init__(self, email="jesus_lqq@163.com", *args, **kwargs): self.email = email super(logit, self).__init__(*args, *kwargs) def notify(self): # 发送一封Email到self.email pass
@email_logit和@logit产生同样的效果,只是前者会发送email。
小结 以上内容学习了*args和**kwargs作用和区别,高阶函数,Debug调试,生成器和装饰器的原理和应用。学会不是目的,应用才是王道。
参考