python常考的语言特性

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值