欢迎来到魔幻小生的博客

python 进阶编程知识

列表表达式(List Comprehension)

列表表达式是一种以简洁语法创建或操作列表的方法。

[expression for item in list if xxx else yyy]

例如输出一个单词中所有字符:

def output_letter(letter):
   return [l for l in letter]

if __name__ == "__main__":
    print(output_letter('kevin'))

image

例子2:输出列表中包含字母k的字符

def output_letter(letter):
   return [l for l in letter if 'k' in l]
   
if __name__ == "__main__":
    print(output_letter(['kevin', 'did', 'automation', 'well']))

image

匿名函数(lambda)

当你的函数逻辑非常少时,你无须再定义一个函数,可采用匿名函数来减少代码量。

lambda arguments : expression

如计算两数之和:

sum = lambda x, y: x + y

print(sum(1, 2))

如计算列表中每个元素的平方:

a = lambda l: [item * item for item in l]

print(a([1, 2, 3, 4]))

自省/反射(Reflection)

在编程中,自省是一种在运行时查找有关对象的信息的能力;而反射则更进一步,它使对象能够在运行时进行修改。

自省和反射是 Python 中非常重要的概念,我们可以通过自省和反射来实现很多高级功能,例如动态查找待运行测试用例。

type

返回对象类型

>>> type(7)
<class 'int'>
>>> type(2.0)
<class 'float'>
>>> type(int)
<class 'type'>

dir

返回对象的属性和方法列表

if __name__ == "__main__":
    my_list = [1, 2, 3]
    print(dir(my_list))
    print(dir(my_list).__class__)

image

id

返回对象的唯一标识符

if __name__ == "__main__":
    name = "kevin"
    print(id(name))
#输出
140245720259120

inspect

inspect 模块提供了一些有用的函数帮助获取对象的信息,例如模块、类、方法、函数、回溯、帧对象,以及代码对象。

例如它可以帮助你检查类的内容,获取某个方法的源代码,取得并格式化某个函数的参数列表,或者获取你需要显示的回溯的详细信息。

这里简单举个例子:

import inspect
 
def my_function(x, y):
    return x + y
 
print(inspect.getsource(my_function))  # 获取函数的源代码
print(inspect.signature(my_function))  # 获取函数的签名信息,包括参数等

闭包(closure)

闭包是一个概念,是指在能够读取其他函数内部变量的函数。

def outer():
    cheer = 'hello '
    def inner(name):
        return cheer + name
    return inner

if __name__ == "__main__":
    #输出hello kevin
    print(outer()('kevin'))

以上代码的意思如下:我定义了一个外部函数 outer 和一个内部函数 inner;在外部函数 outer 内部,我又定义了一个局部变量 cheer(并给定初始值为hello);然后我在内部函数 inner 里引用了这个局部变量 cheer。最后 outer 函数的返回值是 inner 函数本身。

在本例的调用里,outer 函数接受了两个参数,第一个参数为空,第二个参数为 kevin。那么outer() 的返回值就是 inner。所以 outer()('kevin') 的返回值就是 inner('kevin')。

而闭包在 Python 中的经典应用就是装饰器,而装饰器使 Python 代码能够夹带很多“私货”,下面我们就来看下装饰器的应用。

装饰器(decorator)

装饰器是闭包的一个经典应用。装饰器(decorator)在 python 中用来扩展原函数的功能,目的是在不改变原来函数代码的情况下,给函数增加新的功能。

如我们有一个计算N个数字之和的函数:

def sum(*kwargs):
    total = 0
    for ele in kwargs:
        total = total + ele
    return total

现在我们加了需求,还要记录这个函数的开始时间和结束时间,将代码修改如下:

import time

def sum(*kwargs):
    print('function start at {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) ))
    total = 0
    for ele in kwargs:
        total = total + ele
    print('function end at {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) ))
    return total

if __name__ == "__main__":
    print(sum(1,2,3,4))

后来发现记录函数开始和结束时间的功能非常好用,准备把该功能加到每一个运行函数中,如果给每一个函数都加这样的代码就会非常麻烦。

于是我们把计算的函数sum的函数单独抽取出来不变,把时间处理的语句另行定义函数处理。

import time

# 这个是外函数
def record_time(func):
    def wrapper(*kwargs):
        print('function start at {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) ))
        total = func(*kwargs)
        print('function end at {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) ))
        return total
    return wrapper

# 这个是我们真正的功能函数
def sum(*kwargs):
    total = 0
    for ele in kwargs:
        total = total + ele
    time.sleep(2)
    return total


if __name__ == "__main__":
    # 外函数,内函数,和功能函数一起,实现了不改变功能函数的前提下,给功能函数加功能的操作。
    print(record_time(sum)(1,2,3,4))

image

这样我们的功能函数sum无须修改,只需要修改 record_time 这个函数。在不改变原有函数代码的基础上,增加、改变原有函数的功能。

语法糖

Python 中为了让大家写起来方便,给了装饰器一个语法糖。使用语法糖后,在调用函数时,我们就无须再写这个装饰器函数了,转而直接写我们的功能函数就可以了。

例子如下:

import time

def record_time(func):
    def wrapper(*kwargs):
        print('function start at {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) ))
        total = func(*kwargs)
        print('function end at {}'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) ))
        return total
    return wrapper

#注意这一行,我们把record_time这个函数装饰到sum函数上。
@record_time
def sum(*kwargs):
    total = 0
    for ele in kwargs:
        total = total + ele
    time.sleep(2)
    return total

if __name__ == "__main__":
    #注意此次无须再写record_time了,这样有利于大家把关注点放在功能函数本身。
    print(sum(1,2,3,4))

有了装饰器,我们就可以做很多额外的工作,例如插入日志、做事务处理、利用装饰器给测试用例打标签等。

posted @   魔幻小生  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示