Intermediate Python Notes(上)

本文介绍了Python中*args和**kwargs的用法,它们用于处理函数的不定数量参数。接着讨论了Generator迭代器的概念,包括可迭代对象、迭代器和迭代过程。还详细阐述了map、filter和reduce函数的功能。此外,文章探讨了set数据结构的使用,并讲解了Python装饰器的基本原理,包括无参数和带参数的装饰器及其在登录授权和日志记录等场景的应用。
摘要由CSDN通过智能技术生成

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

使用场景

    1. 登录授权

装饰器用的很多的地方就是检查某人是否登录,从而可以访问某些站点,在flask框架中到处都是。。

def requires_auth(f):
    @wraps(f)
    def decorated(*args,**kwargs):
        auth=request.authorizaton # 一个全局变量
        if not auth: # 如果还没登录
            authenticate()  # 就进行登录验证
        return f(*args,**kwargs)
        
    return decorated
    1. 日志

日志也是运用装饰器的一大特点

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值