pythonlru
A. python导入模块或包需要注意哪些点
Python是一种面向对象的编程语言,里面包含有丰富强大的库,想要学习Python开发,首先需要学习如何导入模块或包。下面就跟大家一起讨论下Python导入模块的几种方法:
常规导入
最常用的导入方式,大概是这样的:
import sys
只需要使用 import ,然后指定希望导入的模块或包即可。用这种方法导入的好处是可以一次性导入多个包或模块:
import os, sys, time
虽然这节省了空间,但是却违背了Python风格指南。 Python风格指南建议将每个导入语句单独成行 。
有时在导入模块时,你想要重命名这个模块。这个功能很容易实现:
import sys as system
print(system.platform)
上面的代码将我们导入的 sys 模块重命名为 system 。我们可以按照和以前一样的方式调用模块的方法,但是可以用一个新的模块名。也有某些子模块必须要使用点标记法才能导入。
import urllib.error
这个情况不常见,但是对此有所了解总是没有坏处的。
使用from语句导入
有时我们只想要导入一个模块或库中的某个部分。那么Python是如何实现这点:
from functools import lru_cache
上面这行代码可以让你直接调用 lru_cache 。如果按常规方式导入 functools ,那么就必须像这样调用 lru_cache :
functools.lru_cache(*args)
根据实际的使用场景,上面的做法可能是更好的。在复杂的代码库中,能够看出某个函数是从哪里导入的这点很有用的。不过,如果你的代码维护的很好,模块化程度高,那么只从某个模块中导入一部分内容也是非常方便和简洁的。
当然,你还可以使用from方法导入模块的全部内容,就像这样:
from os import *
这种做法在少数情况下是挺方便的,但是这样也会打乱你的命名空间。问题在于,你可能定义了一个与导入模块中名称相同的变量或函数,这时如果你试图使用
os 模块中的同名变量或函数,实际使用的将是你自己定义的内容。因此,你最后可能会碰到一个相当让人困惑的逻辑错误。
标准库中我唯一推荐全盘导入的模块只有Tkinter 。
如果你正好要写自己的模块或包,有人会建议你在 __init__.py 文件中导入所有内容,让模块或者包使用起来更方便。我个人更喜欢显示地导入,而非隐式地导入。
你也可以采取折中方案,从一个包中导入多个项:
from os import path, walk, unlinkfrom os import uname, remove
在上述代码中,我们从 os 模块中导入了5个函数。你可能注意到了,我们是通过多次从同一个模块中导入实现的。当然,如果你愿意的话,你也可以使用圆括号一次性导入多个项:
from os import (path, walk, unlink, uname,
remove, rename)
这是一个有用的技巧,不过你也可以换一种方式:
from os import path, walk, unlink, uname, \
remove, rename
上面的反斜杠是Python中的续行符,告诉解释器这行代码延续至下一行。
相对导入
PEP 328 介绍了引入相对导入的原因,以及选择了哪种语法。具体来说,是使用句点来决定如何相对导入其他包或模块。这么做的原因是为了避免偶然情况下导入标准库中的模块产生冲突。这里我们以PEP 328中给出的文件夹结构为例,看看相对导入是如何工作的:
my_package/
__init__.py
subpackage1/
__init__.py
mole_x.py
mole_y.py
subpackage2/
__init__.py
mole_z.py
mole_a.py
在本地磁盘上找个地方创建上述文件和文件夹。在顶层的 __init__.py 文件中,输入以下代码:
from . import subpackage1from . import subpackage2
接下来进入 subpackage1 文件夹,编辑其中的 __init__.py 文件,输入以下代码:
from . import mole_xfrom . import mole_y
现在编辑 mole_x.py 文件,输入以下代码:
from .mole_y import spam as ham
def main():
ham()
最后编辑 mole_y.py 文件,输入以下代码:
def spam():
print('spam ' * 3)
打开终端, cd 至 my_package 包所在的文件夹,但不要进入 my_package 。在这个文件夹下运行Python解释器。我使用的是IPython,因为它的自动补全功能非常方便:
In [1]: import my_package
In [2]: my_package.subpackage1.mole_xOut[2]: <mole
'my_package.subpackage1.mole_x' from
'my_package/subpackage1/mole_x.py'>
In [3]: my_package.subpackage1.mole_x.main()spam spam spam
相对导入适用于你最终要放入包中的代码。如果你编写了很多相关性强的代码,那么应该采用这种导入方式。
你会发现PyPI上有很多流行的包也是采用了相对导入 。还要注意一点,如果你想要跨越多个文件层级进行导入,只需要使用多个句点即可。不过, PEP
328建议相对导入的层级不要超过两层 。
还要注意一点,如果你往 mole_x.py 文件中添加了 if __name__ == ‘__main__’ ,然后试图运行这个文件,你会碰到一个很难理解的错误。编辑一下文件,试试看吧!
from . mole_y import spam as ham
def main():
ham()
if __name__ == '__main__':
# This won't work!
main()
现在从终端进入 subpackage1 文件夹,执行以下命令:
python mole_x.py
如果你使用的是Python 2,你应该会看到下面的错误信息:
Traceback (most recent call last):
File "mole_x.py", line 1, in <mole>
from . mole_y import spam as hamValueError: Attempted relative import in non-package
如果你使用的是Python 3,错误信息大概是这样的:
Traceback (most recent call last):
File "mole_x.py", line 1, in <mole>
from . mole_y import spam as hamSystemError: Parent mole '' not loaded, cannot perform relative import
这指的是, mole_x.py 是某个包中的一个模块,而你试图以脚本模式执行,但是 这种模式不支持相对导入 。
如果你想在自己的代码中使用这个模块,那么你必须将其添加至Python的导入检索路径(import search path)。最简单的做法如下:
import syssys.path.append('/path/to/folder/containing/my_package')import my_package
注意,你需要添加的是 my_package 的上一层文件夹路径,而不是 my_package 本身。原因是 my_package 就是我们想要使用的包,所以如果你添加它的路径,那么将无法使用这个包。
我们接下来谈谈可选导入。
可选导入(Optional imports)
如果你希望优先使用某个模块或包,但是同时也想在没有这个模块或包的情况下有备选,你就可以使用可选导入这种方式。这样做可以导入支持某个软件的多种版本或者实现性能提升。以 github2包 中的代码为例:
try:
# For Python 3
from http.client import responsesexcept ImportError: # For Python 2.5-2.7
try:
from httplib import responses # NOQA
except ImportError: # For Python 2.4
from BaseHTTPServer import BaseHTTPRequestHandler as _BHRH
responses = dict([(k, v[0]) for k, v in _BHRH.responses.items()])
lxml 包也有使用可选导入方式:
try:
from urlparse import urljoin
from urllib2 import urlopenexcept ImportError:
# Python 3
from urllib.parse import urljoin
from urllib.request import urlopen
正如以上示例所示, 可选导入的使用很常见,是一个值得掌握的技巧 。
局部导入
当你在局部作用域中导入模块时,你执行的就是局部导入。如果你在Python脚本文件的顶部导入一个模块,那么你就是在将该模块导入至全局作用域,这意味着之后的任何函数或方法都可能访问该模块。例如:
import sys # global scope
def square_root(a):
# This import is into the square_root functions local scope
import math
return math.sqrt(a)
def my_pow(base_num, power):
return math.pow(base_num, power)
if __name__ == '__main__':
print(square_root(49))
print(my_pow(2, 3))
这里,我们将 sys 模块导入至全局作用域,但我们并没有使用这个模块。然后,在 square_root 函数中,我们将 math
模块导入至该函数的局部作用域,这意味着 math 模块只能在 square_root 函数内部使用。如果我们试图在 my_pow 函数中使用
math ,会引发 NameError 。试着执行这个脚本,看看会发生什么。
使用局部作用域的好处之一,是你使用的模块可能需要很长时间才能导入,如果是这样的话,将其放在某个不经常调用的函数中或许更加合理,而不是直接在全局作
用域中导入。老实说,我几乎从没有使用过局部导入,主要是因为如果模块内部到处都有导入语句,会很难分辨出这样做的原因和用途。
根据约定,所有的导入语句都应该位于模块的顶部 。
导入注意事项
在导入模块方面,有几个程序员常犯的错误。这里我们介绍两个。
循环导入(circular imports)
覆盖导入(Shadowed imports,暂时翻译为覆盖导入)
先来看看循环导入。
循环导入
如果你创建两个模块,二者相互导入对方,那么就会出现循环导入。例如:
# a.pyimport b
def a_test():
print("in a_test")
b.b_test()
a_test()
然后在同个文件夹中创建另一个模块,将其命名为 b.py 。
import a
def b_test():
print('In test_b"')
a.a_test()
b_test()
如果你运行任意一个模块,都会引发 AttributeError 。这是因为这两个模块都在试图导入对方。简单来说,模块 a 想要导入模块 b
,但是因为模块 b 也在试图导入模块 a (这时正在执行),模块 a 将无法完成模块 b
的导入。我看过一些解决这个问题的破解方法(hack),但是 一般来说,你应该做的是重构代码,避免发生这种情况 。
覆盖导入
当你创建的模块与标准库中的模块同名时,如果你导入这个模块,就会出现覆盖导入。举个例子,创建一个名叫 math.py 的文件,在其中写入如下代码:
import math
def square_root(number):
return math.sqrt(number)
square_root(72)
现在打开终端,试着运行这个文件,你会得到以下回溯信息(traceback):
Traceback (most recent call last):
File "math.py", line 1, in <mole>
import math
File "/Users/michael/Desktop/math.py", line 6, in <mole>
square_root(72)
File "/Users/michael/Desktop/math.py", line 4, in square_root
return math.sqrt(number)AttributeError: mole 'math' has no attribute 'sqrt'
这到底是怎么回事?其实,你运行这个文件的时候,Python解释器首先在当前运行脚本所处的的文件夹中查找名叫 math
的模块。在这个例子中,解释器找到了我们正在执行的模块,试图导入它。但是我们的模块中并没有叫 sqrt 的函数或属性,所以就抛出了
AttributeError 。
B. python函数的闭包怎么理解
1. 闭包的概念
首先还得从基本概念说起,什么是闭包呢?来看下维基上的解释:
复制代码代码如下:
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
....
上面提到了两个关键的地方: 自由变量 和 函数, 这两个关键稍后再说。还是得在赘述下“闭包”的意思,望文知意,可以形象的把它理解为一个封闭的包裹,这个包裹就是一个函数,当然还有函数内部对应的逻辑,包裹里面的东西就是自由变量,自由变量可以在随着包裹到处游荡。当然还得有个前提,这个包裹是被创建出来的。
在通过Python的语言介绍一下,一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包。你在调用函数A的时候传递的参数就是自由变量。
举个例子:
复制代码代码如下:
def func(name):
def inner_func(age):
print 'name:', name, 'age:', age
return inner_func
bb = func('the5fire')
bb(26) # >>> name: the5fire age: 26
这里面调用func的时候就产生了一个闭包——inner_func,并且该闭包持有自由变量——name,因此这也意味着,当函数func的生命周期结束之后,name这个变量依然存在,因为它被闭包引用了,所以不会被回收。
另外再说一点,闭包并不是Python中特有的概念,所有把函数做为一等公民的语言均有闭包的概念。不过像Java这样以class为一等公民的语言中也可以使用闭包,只是它得用类或接口来实现。
更多概念上的东西可以参考最后的参考链接。
2. 为什么使用闭包
基于上面的介绍,不知道读者有没有感觉这个东西和类有点相似,相似点在于他们都提供了对数据的封装。不同的是闭包本身就是个方法。和类一样,我们在编程时经常会把通用的东西抽象成类,(当然,还有对现实世界——业务的建模),以复用通用的功能。闭包也是一样,当我们需要函数粒度的抽象时,闭包就是一个很好的选择。
在这点上闭包可以被理解为一个只读的对象,你可以给他传递一个属性,但它只能提供给你一个执行的接口。因此在程序中我们经常需要这样的一个函数对象——闭包,来帮我们完成一个通用的功能,比如后面会提到的——装饰器。
3. 使用闭包
第一种场景 ,在python中很重要也很常见的一个使用场景就是装饰器,Python为装饰器提供了一个很友好的“语法糖”——@,让我们可以很方便的使用装饰器,装饰的原理不做过多阐述,简言之你在一个函数func上加上@decorator_func, 就相当于decorator_func(func):
复制代码代码如下:
def decorator_func(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator_func
def func(name):
print 'my name is', name
# 等价于
decorator_func(func)
在装饰器的这个例子中,闭包(wrapper)持有了外部的func这个参数,并且能够接受外部传过来的参数,接受过来的参数在原封不动的传给func,并返回执行结果。
这是个简单的例子,稍微复杂点可以有多个闭包,比如经常使用的那个LRUCache的装饰器,装饰器上可以接受参数@lru_cache(expire=500)这样。实现起来就是两个闭包的嵌套:
复制代码代码如下:
def lru_cache(expire=5):
# 默认5s超时
def func_wrapper(func):
def inner(*args, **kwargs):
# cache 处理 bala bala bala
return func(*args, **kwargs)
return inner
return func_wrapper
@lru_cache(expire=10*60)
def get(request, pk)
# 省略具体代码
return response()
不太懂闭包的同学一定得能够理解上述代码,这是我们之前面试经常会问到的面试题。
第二个场景 ,就是基于闭包的一个特性——“惰性求值”。这个应用比较常见的是在数据库访问的时候,比如说:
复制代码代码如下:
# 伪代码示意
class QuerySet(object):
def __init__(self, sql):
self.sql = sql
self.db = Mysql.connect().corsor() # 伪代码
def __call__(self):
return db.execute(self.sql)
def query(sql):
return QuerySet(sql)
result = query("select name from user_app")
if time > now:
print result # 这时才执行数据库访问
上面这个不太恰当的例子展示了通过闭包完成惰性求值的功能,但是上面query返回的结果并不是函数,而是具有函数功能的类。有兴趣的可以去看看Django的queryset的实现,原理类似。
第三种场景 , 需要对某个函数的参数提前赋值的情况,当然在Python中已经有了很好的解决访问 functools.parial,但是用闭包也能实现。
复制代码代码如下:
def partial(**outer_kwargs):
def wrapper(func):
def inner(*args, **kwargs):
for k, v in outer_kwargs.items():
kwargs[k] = v
return func(*args, **kwargs)
return inner
return wrapper
@partial(age=15)
def say(name=None, age=None):
print name, age
say(name="the5fire")
# 当然用functools比这个简单多了
# 只需要: functools.partial(say, age=15)(name='the5fire')
看起来这又是一个牵强的例子,不过也算是实践了闭包的应用。
C. Python性能提升神器!lru_cache的介绍和讲解
我们经常谈论的缓存一词,更多的类似于将硬盘中的数据存放到内存中以至于提高读取速度,比如常说的redis,就经常用来做数据的缓存。 Python的缓存(lru_cache)是一种装饰在被执行的函数上,将其执行的结果缓存起来,当下次请求的时候,如果请求该函数的传参未变则直接返回缓存起来的结果而不再执行函数的一种缓存装饰器。
那它和redis的区别在哪?有什么优势?怎么使用? 下面为你讲解
1.现在我们先不使用缓存来写一个求两数之和的函数,并调用执行它两次:
执行结果
可以看到 test 被执行了两次,现在我们加上缓存再进行执行:
执行结果
可以看到 test 函数只被执行了一次,第二次的调用直接输出了结果,使用了缓存起来的值。
2.当我们使用递归求斐波拉契数列 (斐波那契数列指的是这样一个数列:0,1,1,2,3,5,8,它从第3项开始,每一项都等于前两项之和) 的时候,缓存对性能的提升就尤其明显了:
不使用缓存求第40项的斐波拉契数列
执行时间
使用缓存求第40项的斐波拉契数列:
执行时间
两个差距是非常明显的,因为不使用缓存时,相当于要重复执行了很多的函数,而使用了 lru_cache 则把之前执行的函数结果已经缓存了起来,就不需要再次执行了。
查看lru_cache源码会发现它可以传递两个参数: maxsize 、 typed :
代表被lru_cache装饰的方法最大可缓存的结果数量 (被装饰方法传参不同一样,则结果不一样;如果传参一样则为同一个结果) , 如果不指定传参则默认值为128,表示最多缓存128个返回结果,当达到了128个时,有新的结果要保存时,则会删除最旧的那个结果。如果maxsize传入为None则表示可以缓存无限个结果;
默认为false,代表不区分数据类型,如果设置为True,则会区分传参类型进行缓存,官方是这样描述的:
但在python3.9.8版本下进行测试,typed为false时,按照官方的测试方法测试得到的还是会被当成不同的结果处理,这个时候typed为false还是为true都会区别缓存,这与官方文档的描述存在差异:
执行结果
但如果是多参数的情况下,则会被当成一个结果:
执行结果
这个时候设置typed为true时,则会区别缓存:
执行结果
当传参个数大于1时,才符合官方的说法,不清楚是不是官方举例有误
当传递的参数是dict、list等的可变参数时,lru_cache是不支持的,会报错:
报错结果
缓存 缓存位置 是否支持可变参数 是否支持分布式 是否支持过期时间设置 支持的数据结构 需单独安装 redis 缓存在redis管理的内存中 是 是 是 支持5种数据结构 是 lru_cache 缓存在应用进程的内存中,应用被关闭则被清空 否 否 否 字典(参数为:key,结果为:value) 否
经过上面的分析,lru_cache 功能相对于redis来说要简单许多,但使用起来更加方便,适用于小型的单体应用。如果涉及的缓存的数据种类比较多并且想更好的管理缓存、或者需要缓存数据有过期时间(类似登录验证的token)等,使用redis是优于lru_cache的。
D. 有哪些轻型的非关系型数据库
常见的非关系型数据库有:1、mongodb;2、cassandra;3、redis;4、hbase;5、neo4j。其中mongodb是非常着名的NoSQL数据库,它是一个面向文档的开源数据库。
常见的几种非关系型数据库:
1、MongoDB
MongoDB是最着名的NoSQL数据库。它是一个面向文档的开源数据库。MongoDB是一个可伸缩和可访问的数据库。它在c++中。MongoDB同样可以用作文件系统。在MongoDB中,JavaScript可以作为查询语言使用。通过使用sharding MongoDB水平伸缩。它在流行的JavaScript框架中非常有用。
人们真的很享受分片、高级文本搜索、gridFS和map-rece功能。惊人的性能和新特性使这个NoSQL数据库在我们的列表中名列第一。
特点:提供高性能;自动分片;运行在多个服务器上;支持主从复制;数据以JSON样式文档的形式存储;索引文档中的任何字段;由于数据被放置在碎片中,所以它具有自动负载平衡配置;支持正则表达式搜索;在失败的情况下易于管理。
优点:易于安装MongoDB;MongoDB Inc.为客户提供专业支持;支持临时查询;高速数据库;无模式数据库;横向扩展数据库;性能非常高。
缺点:不支持连接;数据量大;嵌套文档是有限的;增加不必要的内存使用。
2、Cassandra
Cassandra是Facebook为收件箱搜索开发的。Cassandra是一个用于处理大量结构化数据的分布式数据存储系统。通常,这些数据分布在许多普通服务器上。您还可以添加数据存储容量,使您的服务保持在线,您可以轻松地完成这项任务。由于集群中的所有节点都是相同的,因此不需要处理复杂的配置。
Cassandra是用Java编写的。Cassandra查询语言(CQL)是查询Cassandra数据库的一种类似sql的语言。因此,Cassandra在最佳开源数据库中排名第二。Facebook、Twitter、思科(Cisco)、Rackspace、eBay、Twitter、Netflix等一些最大的公司都在使用Cassandra。
特点:线性可伸缩;;保持快速响应时间;支持原子性、一致性、隔离性和耐久性(ACID)等属性;使用Apache Hadoop支持MapRece;分配数据的最大灵活性;高度可伸缩;点对点架构。
优点:高度可伸缩;无单点故障;Multi-DC复制;与其他基于JVM的应用程序紧密集成;更适合多数据中心部署、冗余、故障转移和灾难恢复。
缺点:对聚合的有限支持;不可预知的性能;不支持特别查询。
3、Redis
Redis是一个键值存储。此外,它是最着名的键值存储。Redis支持一些c++、PHP、Ruby、Python、Perl、Scala等等。Redis是用C语言编写的。此外,它是根据BSD授权的。
特点:自动故障转移;将其数据库完全保存在内存中;事务;Lua脚本;将数据复制到任意数量的从属服务器;钥匙的寿命有限;LRU驱逐钥匙;支持发布/订阅。
优点:支持多种数据类型;很容易安装;非常快(每秒执行约11万组,每秒执行约81000次);操作都是原子的;多用途工具(在许多用例中使用)。
缺点:不支持连接;存储过程所需的Lua知识;数据集必须很好地适应内存。
4、HBase
HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。
HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。
5、neo4j
Neo4j被称为原生图数据库,因为它有效地实现了属性图模型,一直到存储层。这意味着数据完全按照白板的方式存储,数据库使用指针导航和遍历图。Neo4j有数据库的社区版和企业版。企业版包括Community Edition必须提供的所有功能,以及额外的企业需求,如备份、集群和故障转移功能。
特点:它支持唯一的约束;Neo4j支持完整的ACID(原子性、一致性、隔离性和持久性)规则;Java API: Cypher API和本机Java API;使用Apache Lucence索引;简单查询语言Neo4j CQL;包含用于执行CQL命令的UI: Neo4j Data Browser。
优点:容易检索其相邻节点或关系细节,无需连接或索引;易于学习Neo4j CQL查询语言命令;不需要复杂的连接来检索数据;非常容易地表示半结构化数据;大型企业实时应用程序的高可用性;简化的调优。
缺点:不支持分片
E. python matplotlib 依赖哪些包
Matplotlib 需要大量的依赖:
Python(>= 2.7 or >= 3.4)
NumPy(>= 1.7.1)
setuptools
dateutil(>= 2.0)
pyparsing
libpng(>= 1.2)
pytz
FreeType (>= 2.3)
cycler(>= 0.10.0)
six
backports.functools_lru_cache
(仅 Python 2.7 )
subprocess32
(仅 Python2.7 , 仅 Linux 和 macOS 平台)
F. python教程哪里下载
一、Python入门到进阶的 廖雪峰 Python & JS & Git 教程PDF版 链接:G. python哪些标准库
标准库比较多 功能也不同:
标准库
sys
系统相关的参数和函数。 sys 库一般用来访问和修改系统相关信息,比如查看 python 版本、系统环境变量、模块信息和 python 解释器相关信息等等。
os
操作系统接口模块。这个库提供了访问操作系统相关依赖的方式,比如输入输出操作、读写操作、操作系统异常错误信息、进程线程管理、文件管理、调度程序等等。
re
正则表达式操作。这个库是我喜欢并且经常会用到的库,在对大量字符串进行处理的时候用正则表达式是最快速有效的方式,但是正则表达式的学习曲线较高,有兴趣的朋友可以访问这个网站学习。
math
数学函数库。 math 库提供了对 C 语言标准定义的数学函数访问,比如数论(Number-theoretic)的各种表示方法、幂和对数函数(Power and logarithmic functions)、三角函数(Trigonometric functions)、常量圆周率(π)和自然常数(e)等等。
random
生成伪随机数。
伪随机数与随机数(真随机数)不同的是执行环境,随机数是真实世界中通过物理过程实践得出结论,而伪随机数是通过计算机的特定算法生成的数,所以这个过程是可预测的、有规律的,只是循环周期较长,并不能与现实场景相切合。
random库提供生成随机数,可以模拟现实世界中随机取数、随机抽奖等等。
logging
日志记录工具。这个库提供了对应用程序和库函数的日志记录,日常开发中我们经常需要通过日志打印出当前程序的运行状态,实时查看可能出现的堆栈异常和错误信息。
json
Json 编码和解码器。 json 库提供了对 json 数据的支持,日常开发中我们做前后端分离需要对传输数据 json 进行序列化和反序列化操作,以保证对数据的完整性和有效性,而序列化和反序列化其实就是编码和解码的过程。
pickle
Python 对象序列化库。 pickle 库支持对 python 对象进行序列化和反序列化操作,当我们需要将处理好的对象保存到文件或数据库中时,就可以将其序列化成二进制数据,从而更好的保存起来。
shelve
Python 对象持久化。简单的数据存储方案。
socket
底层网络接口。 socket(套接字) 库提供了标准的BSD(伯克利套接字) Socket API,可以通过访问底层操作系统 Socket 的相关接口进行网络通讯。
datetime
基本日期和时间类型库。该库提供了各种简单和复杂的方式处理日期和时间,日常我们会用时间测算时间消耗、复杂度,对存储的创建时间和修改时间也需要进一步说明,对计时器的描述和控制也需要用到该库。
hashlib
安全哈希和消息摘要。摘要算法 其实就是对某些数据进行加密(不可逆的加密算法),因为被加密的数据无法破解,所以就能防止被篡改。常见的摘要算法有 MD5、SHA1,一般我们会用 MD5 对用户口令进行加密,防止盗用后被轻易破解;而 SHA1 与 MD5 类似,但是 SHA1 会产生更长的长度,也更安全,但是算法的复杂性通常伴随着存储空间和时间的消耗。要说比SHA1更长的字符长度,还有 SHA224、SHA256、SHA384 和 SHA512,看名字就能知道。
大家都知道无论算法生成的字符长度如何都有可能发生碰撞(被破解),这是不可避免的,所以具体场景具体情况而定。
configparser
配置文件解析器。 configparser 库可以轻松定制配置文件,通过解析配置文件的信息我们就可以全局访问相关配置。
urllib
URL 处理模块。 urllib 库集成了处理 URLs(统一资源定位符)的各种模块:
URL urllib.request URL robots.txt urllib 库对访问网络有很好的支持,提供了对数据的访问和处理、文件的上传和下载、记录 cookie 和 session 等等。
itertools
为高效循环而创建迭代器的函数。 itertools 库也是经常需要用到,当我们要对某些数进行 for-in 时就需要先将其处理成一个可迭代对象,之后我们才能进行遍历操作。
collections
容器数据类型库。 collections 库提供了对所有容器数据类型的支持,包括 dict, list, set 和 tuple。我们可以用此库对不同数据类型进行操作,常有的函数方法有这些:
namedtuple() 创建命名元组子类的工厂函数 deque 类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop) ChainMap 类似字典(dict)的容器类,将多个映射集合到一个视图里面 Counter 字典的子类,提供了可哈希对象的计数功能 OrderedDict 字典的子类,保存了他们被添加的顺序 defaultdict 字典的子类,提供了一个工厂函数,为字典查询提供一个默认值 UserDict 封装了字典对象,简化了字典子类化 UserList 封装了列表对象,简化了列表子类化 UserString 封装了列表对象,简化了字符串子类化 functools
高阶函数和可调用对象上的操作。该库主要调用高阶函数,是常规函数的一种补充。目前库中包含以下几种函数:
cmp_to_key lru_cache total_ordering partial partialmethod rece singledispatch update_wrapper wraps threading
线程并行库。 threading 库支持线程和多线程的操作,针对多线程并发的问题可以给数据加同步锁,一次只能让一个线程处理数据,从而避免出现数据读写混乱。
在 CPython 解释器上,因为GIL(全局解释器锁)锁机制的存在的,被设计成线程安全,所以同一时间只能执行一个线程,这就导致了多线程不能发挥出计算机的多核特性。
multiprocessing
进程并行库。 multiprocessing 库与 threading 库很类似,不同的是进程库可以创建子进程避开 GIL,从而弥补线程库存在的劣势和发挥计算机的多核特性。
timeit
测量小代码片段的执行时间。此库主要用来计算运行代码的时间消耗,支持多种方式传入参数。
atexit
退出处理器。当处理一个函数需要立马退出时可以使用该库。
abc
抽象基类。 abc 库定义抽象基类,以便其他类派生出新类。比如 collections 容器库中就有此派生出的 collections.abc 类,派生出来的类可以进一步实现。
asyncio
异步IO库。 asyncio 库是一个用 async/await 关键字编写并发的库,为多个异步框架提供基础功能,能够实现高性能的网络、Web服务器、数据库连接和分布式任务队列等。
浅层和深层复制操作。 库提供对对象的拷贝,我们都知道要制作对象副本,是无法通过简单值传递创建新变量的方式做到,因为新变量所指向的内存空间依旧是原对象本身,所以对新变量进行任何操作都会改变原对象。那么, 库就提供了制作对象副本的各种方法,会开辟一个新的内存空间存放副本对象,修改操作不会对原对象有任何干预。
csv
csv(Comma Separated Values)文件读写库。此库支持以纯文本的形式存储表格数据(数字和文本)。
operator
标准运算符替代函数库。此库是将 python 自有的运算符作为有效函数,比如表达式 x+y 可以用函数 operator.add(x, y) 表示;比如表达式 a*b 可以用函数 operator.mul(a, b) 表示,等等。
enum
枚举库。 enum 库支持创建枚举类来存储大量同类型的不可变常量,以便其他函数调用。创建出来的枚举类是可迭代对象,所以可以用 for-in 枚举出所有常量。
heapq
堆队列算法。这个模块提供了堆队列算法的实现,也称为优先队列算法。优先队列中的每个元素都有各自的优先级,优先级最高的元素最先得到服务。所以当我们要求前n最大/最小值的时候就可以用此算法来实现, heapq 库中也提供了相应函数实现。
http
HTTP 模块。 http 模块是一个包,收集了多个处理超文本传输协议的模块:
urllib.request http 模块通过 http.HTTPStatus 枚举定义了HTTP状态码 以及相关联消息。
profile、pstats
性能分析工具。 profile 模块提供了 profile 和 cProfile 两种不同实现的性能分析工具,可用来描述程序各个部分的执行时间和频率,统计后的信息可以通过 pstats 模块保存并使用。
ssl
TLS/SSL(传输安全协议)。此模块提供对安全协议的支持,通过应用上下文,可将 TLS(传输层安全性协议)或其前身 SSL(安全套接层)支持安全协议,能为互联网通信提供安全和数据完整性保障。一般 HTTPS 协议都支持 TLS/SSL 加密。
unitest
单元测试框架。 unitest 库常用于单元测试,受到 JUnit 和其他主流测试库的启发, unitest 库的功能和函数与它们有着相似的风格。
uuid
UUID库。 uuid 库主要用途是生成随机字符串,库中有多个版本的 UUID 对象方法,比如版本 1、3、4 和 5 的 uuid1() 、 uuid3() 、 uuid4() 和 uuid5() 。需要注意的是,如果要生成随机字符串,可以使用 uuid1() 和 uuid4() ,但是 uuid1() 会存在隐私风险,因为生成的原理里边包含用户访问计算机的网络地址,而 uuid4() 是通过随机字符生成。
希望可以帮助到你。