python基础篇(二十)——Python中的一些易混淆点总结(完结)
Posted 一计之长
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python基础篇(二十)——Python中的一些易混淆点总结(完结)相关的知识,希望对你有一定的参考价值。
前言
接着上篇文章,我们继续为大家介绍Python中易混淆的知识点。
一、lambda表达式
lambda表达式是一行函数。它们在其他语言中也被称为匿名函数。如果你不想在程序中对一个函数使用两次,你也许会想用lambda表达式,它们和普通的函数完全一样。具体的语法如下:
lambda 参数:操作(参数)
我们通过一个案例来详细说明该语法的具体应用:`
add = lambda x, y: x + y
print(add(3, 5))
具体执行结果如下:
这还有一些lambda表达式的应用案例,可以在一些特殊情况下使用:
- 列表排序
- 这还有一些lambda表达式的应用案例,可以在一些特殊情况下使用:
a = [(1, 2), (4, 1), (9, 10), (13, -3)]
a.sort(key=lambda x: x[1])
print(a)
具体执行结果如下:
二、For - Else
循环是任何语言的一个必备要素。同样地,for循环就是Python的一个重要组成部分。然而还有一些东西是初学者并不知道的。我们将一个个讨论一下。我们先从已经知道的开始。我们知道可以像这样使用for循环:
fruits = [\'apple\', \'banana\', \'mango\']
for fruit in fruits:
print(fruit.capitalize())
具体执行结果如下:
这是一个for循环非常基础的结构。现在我们继续看看,Python的for循环的一些鲜为人所知的特性。for循环还有一个else从句,我们大多数人并不熟悉。这个else从句会在循环正常结束时执行。这意味着,循环没有遇到任何break. 一旦你掌握了何时何地使用它,它真的会非常有用。我自己对它真是相见恨晚。有个常见的构造是跑一个循环,并查找一个元素。如果这个元素被找到了,我们使用break来中断这个循环。有两个场景会让循环停下来。
- 第一个是当一个元素被找到,break被触发。
- 第二个场景是循环结束。
现在我们也许想知道其中哪一个,才是导致循环完成的原因。一个方法是先设置一个标记,然后在循环结束时打上标记。另一个是使用else从句。这就是for/else循环的基本结构:
for item in container:
if search_something(item):
process(item)
break
else:
not_found_in_container()
考虑下这个简单的案例,它是我从官方文档里拿来的:
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, \'equals\', x, \'*\', n/x)
break;
具体执行结果如下:
它会找出2到10之间的数字的因子。现在是趣味环节了。我们可以加上一个附加的else语句块,来抓住质数,并且告诉我们:
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, \'equals\', x, \'*\', n/x)
break
else:
print(n, \'is a prime number\')
具体执行结果如下:
三、协程
Python中的协程和生成器很相似但又稍有不同。主要区别在于:
这样做不仅快而且不会给内存带来压力,因为我们所需要的值都是动态生成的而不是将他们存储在一个列表中。更概括的说如果现在我们在上面的例子中使用yield便可获得了一个协程。协程会消费掉发送给它的值。Python实现的grep就是个很好的例子:
def grep(pattern):
print("Searching for", pattern)
while True:
line = (yield)
if pattern in line:
print(line)
search = grep(\'coroutine\')
next(search)
具体执行结果如下:
发送的值会被yield接收。我们为什么要运行next()方法呢?这样做正是为了启动一个协程。就像协程中包含的生成器并不是立刻执行,而是通过next()方法来响应send()方法。因此,你必须通过next()方法来执行yield表达式。我们可以通过调用close()方法来关闭一个协程。像这样:
def grep(pattern):
print("Searching for", pattern)
while True:
line = (yield)
if pattern in line:
print(line)
search = grep(\'coroutine\')
next(search)
search = grep(\'coroutine\')
search.close()
具体执行结果如下:
四、函数缓存 (Function caching)
函数缓存允许我们将一个函数对于给定参数的返回值缓存起来。当一个I/O密集的函数被频繁使用相同的参数调用的时候,函数缓存可以节约时间。在Python 3.2版本以前我们只有写一个自定义的实现。在Python 3.2以后版本,有个lru_cache的装饰器,允许我们将一个函数的返回值快速地缓存或取消缓存。我们来看看,Python 3.2前后的版本分别如何使用它。
我们来实现一个斐波那契计算器,并使用lru_cache。
from functools import lru_cache
@lru_cache(maxsize=32)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
print([fib(n) for n in range(10)])
具体执行结果如下:
那个maxsize参数是告诉lru_cache,最多缓存最近多少个返回值。我们也可以轻松地对返回值清空缓存,通过这样:
fib.cache_clear()
五、上下文管理器(Context managers)
上下文管理器允许你在有需要的时候,精确地分配和释放资源。使用上下文管理器最广泛的案例就是with语句了。想象下你有两个需要结对执行的相关操作,然后还要在它们中间放置一段代码。上下文管理器就是专门让你做这种事情的。举个例子:
with open(\'some_file\', \'w\') as opened_file:
opened_file.write(\'Hola!\')
上面这段代码打开了一个文件,往里面写入了一些数据,然后关闭该文件。如果在往文件写数据时发生异常,它也会尝试去关闭文件。上面那段代码与这一段是等价的:
file = open(\'some_file\', \'w\')
try:
file.write(\'Hola!\')
finally:
file.close()
当与第一个例子对比时,我们可以看到,通过使用with,许多样板代码(boilerplate code) 被消掉了。 这就是with语句的主要优势,它确保我们的文件会被关闭,而不用关注嵌套代码如何退出。
上下文管理器的一个常见用例,是资源的加锁和解锁,以及关闭已打开的文件(就像我已经展示给你看的)。让我们看看如何来实现我们自己的上下文管理器。这会让我们更完全地理解在这些场景背后都发生着什么。
1、基于类的实现
一个上下文管理器的类,最起码要定义__enter__
和__exit__
方法。让我们来构造我们自己的开启文件的上下文管理器,并学习下基础知识。
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)
def __enter__(self):
return self.file_obj
def __exit__(self, type, value, traceback):
self.file_obj.close()
with File(\'demo.txt\', \'w\') as opened_file:
opened_file.write(\'Hola!\')
具体执行结果如下:
我们的__exit__函数
接受三个参数。这些参数对于每个上下文管理器类中的__exit__方法
都是必须的。我们来谈谈在底层都发生了什么。
我们尝试下在__exit__方法
中处理异常:
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)
def __enter__(self):
return self.file_obj
def __exit__(self, type, value, traceback):
print("Exception has been handled")
self.file_obj.close()
return True
with File(\'demo.txt\', \'w\') as opened_file:
opened_file.undefined_function()
具体执行结果如下:
我们的__exit__方法
返回了True
,因此没有异常会被with语句
抛出。这还不是实现上下文管理器的唯一方式。还有一种方式,我们会在下一节中一起看看。
3、基于生成器的实现
我们还可以用装饰器(decorators)和生成器(generators)来实现上下文管理器。Python有个contextlib模块
专门用于这个目的。我们可以使用一个生成器函数来实现一个上下文管理器,而不是使用一个类。让我们看看一个基本的,没用的例子:
from contextlib import contextmanager
@contextmanager
def open_file(name):
f = open(name, \'w\')
yield f
f.close()
with open_file(\'some_file\') as f:
f.write(\'hola!\')
具体执行结果如下:
这个实现方式看起来更加直观和简单。然而,这个方法需要关于生成器、yield和装饰器的一些知识。在这个例子中我们还没有捕捉可能产生的任何异常。它的工作方式和之前的方法大致相同。
总结
本文给大家介绍了Python中的lambda表达式、FOR-ELSE语句,另外又介绍了协程、函数缓存;最后介绍了上下文管理器。至此,Python中的易混淆的知识点已经介绍完毕。这些都是Python初学者常遇到的问题,当大家遇到问题的时候,可以来看看这些文章,涵盖了大多数初学者遇到的问题。Python是一门注重实际操作的语言,它是众多编程语言中最简单,也是最好入门的。当你把这门语言学会了,再去学习java、go以及C语言就比较简单了。当然,Python也是一门热门语言,对于人工智能的实现有着很大的帮助,因此,值得大家花时间去学习。生命不息,奋斗不止,我们每天努力,好好学习,不断提高自己的能力,相信自己一定会学有所获。加油!!!
以上是关于python基础篇(二十)——Python中的一些易混淆点总结(完结)的主要内容,如果未能解决你的问题,请参考以下文章
python全栈开发基础第二十篇利用multiprocessing模块开进程