01 *args and **kwargs
1. 他们都是用来给函数传递不定数量参数的“占位“参数
- *args: 非key-value形式的不定数量参数
- **kwargs: key-value形式的不定数量参数
这三种参数的标准顺序为:
func(fix_args,*args,**kwargs)
def test_var_args(fix_arg,*args):
print("the fixed arg passed in is: ",fix_arg)
for arg in args:
print("another arg through *args is: ",arg)
def test_var_kwargs(name,**kwargs):
print("Your name is: ",name)
for key,value in kwargs.items():
print("Your {0} is {1}.".format(key,value))
test_var_args("Alice","Bob","foo")
test_var_kwargs("Andy",sex="male",role="student")
the fixed arg passed in is: Alice
another arg through *args is: Bob
another arg through *args is: foo
Your name is: Andy
Your sex is male.
Your role is student.
2. 也可以用他们来把所·有参数作为一个整体封装,传入函数
def test_args_and_kwargs(arg1,arg2,arg3):
print("operation: ",arg1)
print("num1: ",arg2)
print("num2: ",arg3)
args=("add",2,3)
kwargs={"arg1":"minus","arg2":3,"arg3":1}
test_args_and_kwargs(*args)
test_args_and_kwargs(**kwargs)
operation: add
num1: 2
num2: 3
operation: minus
num1: 3
num2: 1
02 Generator 迭代器
熟悉以下三个概念:
- 可迭代对象(iterable):在Python中的任意对象,只要提供了
__iter__
或者__getitem__
方法,它就是可迭代对象 - 迭代器(iterator):在Python中的任意对象,只要提供了
__next__
方法,它就是迭代器 - 迭代(iteration):代指迭代这个过程
生成器是一种特殊的迭代器,我们只能对它进行一次迭代,因为它并没有把所有生成的值都放进内存里了,而是在运行时生成值。
我们要么在运行时用个for循环,要么把这些值通过可迭代对象保存起来。
def generator_func():
for i in range(3):
yield i
# generator version
def fibbo(n):
a=b=1
for i in range(n):
yield a
a,b=b,a+b
gen=generator_func() # 生成器是一个特殊的迭代器,只能迭代一遍!
for i in range(3):
print(next(gen))
# 一旦迭代超限,就会抛出StopIteration异常
print(next(gen))
0
1
2
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-34-2caf12b0fbda> in <module>()
4
5 # 一旦迭代超限,就会抛出StopIteration异常
----> 6 print(next(gen))
StopIteration:
for item in generator_func():
print (item)
0
1
2
for x in fibbo(5):
print(x)
1
1
2
3
5
str
不是迭代器(iterator),而是可迭代对象(iterable),因为str对象内部提供了__iter__
方法。
我们可以通过调用.iter()
方法来得到可迭代对象的迭代器。
test_str="foo"
next(test_str)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-39-7b96760ca611> in <module>()
1 test_str="foo"
----> 2 next(test_str)
TypeError: 'str' object is not an iterator
test_iterator=iter(test_str)
print(next(test_iterator))
print(next(test_iterator))
print(next(test_iterator))
f
o
o
03 Map, Filter & Reduce
- map的作用是将一个函数映射到一个输入列表的所有元素上,规范为
map(func_to_apply,list_of_input)
items=[1,2,3]
squares=[]
for i in items:
squares.append(i**2)
print(squares)
# ==========等价于=============
# 在py3中,map返回的是一个迭代器对象
map_squares=list(map(lambda x: x**2, items))
print(map_squares)
print("======================")
# map也适合于输入列表中的每一个item都是一个函数,在py中,一切皆对象
def multiply(x):
return x**2
def add(x):
return 2*x
funcs=[multiply,add]
for i in range(5):
res=list(map(lambda x: x(i),funcs))
print(res)
[1, 4, 9]
[1, 4, 9]
======================
[0, 0]
[1, 2]
[4, 4]
[9, 6]
[16, 8]
- filter 的作用即过滤输入列表中的item,返回一个符合要求的所有记录的列表,符合要求即函数映射该item时返回为True
num_list=range(-5,5)
# filter返回的也是一个迭代器
num_no_greater_than_zero=list(filter(lambda x: x<=0,num_list))
print(num_no_greater_than_zero)
[-5, -4, -3, -2, -1, 0]
- reduce的作用是对一个输入列表进行一系列计算并返回结果,这个和map有点类似,不过会将输入列表中的每个item总和起来
from functools import reduce
res=reduce(lambda x,y:x+y,[1,2,3,4])
print(res)
10
04 set(集合)数据结构
# 寻找一个列表中有重复的项
some_list = ['a', 'b', 'c', 'b', 'd', 'm', 'n', 'n']
duplicates=set([x for x in some_list if some_list.count(x)>1])
print(duplicates)
print("=========================")
# =========集合的交集、差集============
valid=set(["a","b","c"])
input_set=set(["a","c"])
print("intersection: ",input_set.intersection(valid))
print("difference: ",valid.difference(input_set))
{'b', 'n'}
=========================
intersection: {'a', 'c'}
difference: {'b'}
05 装饰器(decorator)
在python中,一切事物皆对象,我们可以给函数赋值(funca_alias=funca
),也可以在函数里面定义函数
def hi():
print("Hi, there! You are inside the hi() function!")
# inside_a 和 inside_b 在外部是无法访问的
def inside_a():
return "Now, you are inside the inside_a() function!"
def inside_b():
return "Now, you are inside the inside_b() function!"
print(inside_a())
print(inside_b())
print("Okay, you return back to the scope of hi() function!")
hi()
inside_a() # 外部无法访问
Hi, there! You are inside the hi() function!
Now, you are inside the inside_a() function!
Now, you are inside the inside_b() function!
Okay, you return back to the scope of hi() function!
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-22-a10d78794ee9> in <module>()
1 hi()
----> 2 inside_a()
NameError: name 'inside_a' is not defined
# 其实我们不一定非得在一个函数里面返回另一个函数,而是可以返回函数对象
def hello(name="Andy"):
print("Hi, %s! You are inside the hello() function!"%name)
# inside_a 和 inside_b 在外部是无法访问的
def inside_a():
return "Now, you are inside the inside_a() function!"
def inside_b():
return "Now, you are inside the inside_b() function!"
if name=="Andy":
return inside_a
else:
return inside_b
a=hello()
print(a) # 此时a是一个函数对象
print(a())
Hi, Andy! You are inside the hello() function!
<function hello.<locals>.inside_a at 0x00000286F7C216A8>
Now, you are inside the inside_a() function!
这个特性可以生成python中所谓的钩子函数
def hola():
return "Hola!"
def do_sth_before_hola():
print("I am doing sth before executing hola() !")
print(hola())
do_sth_before_hola()
I am doing sth before executing hola() !
Hola!
第一个装饰器
def my_decorator(a_func):
def wrap_the_func():
print("I am doing sth before executing a_func() !")
a_func()
print("I am doing sth after executing a_func() !")
return wrap_the_func
def func_to_be_decorated():
print("I am the function to be decorated!")
decorated_func=my_decorator(func_to_be_decorated)
print(decorated_func) # 一个函数对象
decorated_func()
<function my_decorator.<locals>.wrap_the_func at 0x00000286F7C21B70>
I am doing sth before executing a_func() !
I am the function to be decorated!
I am doing sth after executing a_func() !
装饰器可以使用python中的@表达方式,即在要被装饰的函数前,加上@name_of_decorator
@my_decorator
def decorated_function_using_at_sign():
print("Hello, there !")
decorated_function_using_at_sign()
# 其实上面就等价于
# decorated_function_using_at_sign=my_decorator(decorated_function_using_at_sign)
# 然后再执行这个被装饰的函数
I am doing sth before executing a_func() !
Hello, there !
I am doing sth after executing a_func() !
wrap_the_func
上面就是一个装饰器的使用范例,但是还有一个问题,decorated_function_using_at_sign.__name__
会是wrap_the_func
,而我们希望输出的是decorated_function_using_at_sign
。
这可以py内置的functools.wraps
来解决。@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
from functools import wraps
def decorator_name(func_name):
@wraps(func_name)
def decorated(*args,**kwargs):
if not can_run:
return "Fuction will not run!"
return func_name(*args,**kwargs)
return decorated
@decorator_name
def func():
return("Function is running")
# flag
can_run=True
print(func())
print(func.__name__)
# flag
can_run=False
print(func())
print(func.__name__)
Function is running
func
Fuction will not run!
func
使用场景
-
- 登录授权
装饰器用的很多的地方就是检查某人是否登录,从而可以访问某些站点,在flask框架中到处都是。。
def requires_auth(f):
@wraps(f)
def decorated(*args,**kwargs):
auth=request.authorizaton # 一个全局变量
if not auth: # 如果还没登录
authenticate() # 就进行登录验证
return f(*args,**kwargs)
return decorated
-
- 日志
日志也是运用装饰器的一大特点
def logit(f):
@wraps(f)
def with_logging(*args,**kwargs):
print(f.__name__+"was called.")
return f(*args,**kwargs)
return with_logging
@logit
def add_func(a,b):
return a+b
result=add_func(1,2)
print(result)
add_funcwas called.
3
带参数的装饰器
@wraps装饰器可以接受一个函数作为输入,其实我们自定义的装饰器也是可以接受输入参数的。
比如在上述的日志装饰器中,我们可以给定一个输入日志文件名参数来指定日志写入文件的位置,怎么做?
再包裹一层!
import time
def logit(log_file_name="./temp.log"):
def logging_decorator(f):
@wraps(f)
def with_logging(*args,**kwargs):
print("start recording log info into %s"%log_file_name)
with open(log_file_name,"a") as file:
file.write(time.asctime(time.localtime(time.time()))+"-->"+f.__name__+"was called.\r\n")
return f(*args,**kwargs)
return with_logging
return logging_decorator
@logit()
def add_func(a,b):
return a+b
@logit(log_file_name="./out.log")
def minus_func(a,b):
return a-b
# 运行以下两条后在相应的文件中记录日志文件
print(add_func(1,2))
print(minus_func(2,1))
start recording log info into ./temp.log
3
start recording log info into ./out.log
1
也可以用类的方式来创建装饰器
from functools import wraps
class logit(object):
def __init__(self,log_file_name="./temp.log"):
self.log_file_name=log_file_name
def __call__(self,func):
@wraps(func)
def with_logging(*args,**kwargs):
print("start recording log info into %s"%self.log_file_name)
with open(self.log_file_name,"a") as file:
file.write(time.asctime(time.localtime(time.time()))+"-->"+func.__name__+"was called.\r\n")
# 在写完日志文件后,甚至可以进行一些其他的通知操作
self.notify()
return func(*args,**kwargs)
return with_logging
def notify(self):
pass
@logit()
def add_func(a,b):
return a+b
@logit(log_file_name="./out.log")
def minus_func(a,b):
return a-b
# 运行以下两条后在相应的文件中记录日志文件
print(add_func(1,2))
print(minus_func(2,1))
start recording log info into ./temp.log
3
start recording log info into ./out.log
1
#==========继承logit,生成新的装饰器============
class email_logit(logit):
def __init__(self,email='admin@myproject.com',log_file_name="./temp.log"):
super(email_logit,self).__init__(log_file_name)
self.email=email
# 重载notify函数
def notify(self):
print("A checkout email has been sent to %s"%self.email)
@email_logit()
def add_func(a,b):
return a+b
@email_logit(email='andy@myproject.com',log_file_name="./out.log")
def minus_func(a,b):
return a-b
# 运行以下两条后在相应的文件中记录日志文件
print(add_func(1,2))
print(minus_func(2,1))
start recording log info into ./temp.log
A checkout email has been sent to admin@myproject.com
3
start recording log info into ./out.log
A checkout email has been sent to andy@myproject.com
1