python 3.7官方文档
py3-cookbook
在线的jupyter lab,点击即可
numpy reshape(-1)解读
1. str
1.1 相邻字符串合并
作为单一表达式组成部分,之间只由空格分隔的多个字符串字面值会被隐式地转换为单个字符串字面值。 也就是说,
("spam " "eggs") == "spam eggs"
1.2 str.lstrip([chars])
返回原字符串的副本,移除其中的前导字符。 chars 参数为指定要移除字符的字符串。 如果省略或为 None,则 chars 参数默认移除空格符。 实际上 chars 参数并非指定单个前缀;而是会移除参数值的所有组合
1.3 str.endswith(suffix[, start[, end]])
如果字符串以指定的 suffix 结束返回 True,否则返回 False。 suffix 也可以为由多个供查找的后缀构成的元组。 如果有可选项 start,将从所指定位置开始检查。 如果有可选项 end,将在所指定位置停止比较
1.4 print()
函数将所有传进来的参数值打印出来. 它和直接输入你要显示的表达式(比如我们之前在计算器的例子里做的)不一样, print() 能处理多个参数,包括浮点数,字符串。 字符串会打印不带引号的内容, 并且在参数项之间会插入一个空格, 这样你就可以很好的把东西格式化, 像这样:
>>> a, b = 0, 1
>>> while a < 1000:
... print(a, end=',')
... a, b = b, a+b
...
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
4.流程控制
>>>for w in words[:]: # Loop over a slice copy of the entire list.
... if len(w) > 6:
... words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']
如果写成 for w in words:,这个示例就会创建无限长的列表,一次又一次重复地插入 defenestrate。
要以序列的索引来迭代,您可以将 range()
和 len()
组合如下:
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
... print(i, a[i])
...
0 Mary
1 had
2 a
3 little
4 lamb
enumerate(iterable, start=0)
4.7.2 关键字参数
当在最后出现形如 **name
的形式参数时,它会接受一个字典(参见 映射类型 --- dict )字典中包含了所有除了与形式参数对应的其他关键字参数。这可以和形如 *name
的形式参数(在下一小节描述)结合,该参数会接受一个包含形式参数列表之外的位置参数的元组。(*name
必须在出现在 **name
之前。)比如,如果我们定义一个这样的函数:
def cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind, "?")
print("-- I'm sorry, we're all out of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
for kw in keywords:
print(kw, ":", keywords[kw])
它可以像这样调用:
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
4.7.4. 解包参数列表
当参数已经在列表或元组中但需要为需要单独位置参数的函数调用解包时,会发生相反的情况。例如,内置的 range()
函数需要单独的 start 和 stop 参数。如果它们不能单独使用,请使用 *
运算符编写函数调用以从列表或元组中解包参数:
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]
4.7.5. Lambda 表达式
可以用 lambda
关键字来创建一个小的匿名函数。这个函数返回两个参数的和: lambda a, b: a+b
。Lambda函数可以在需要函数对象的任何地方使用。它们在语法上限于单个表达式。从语义上来说,它们只是正常函数定义的语法糖。与嵌套函数定义一样,lambda函数可以引用包含范围的变量:
>>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
5.数据结构
5.1
list.sort(key=None, reverse=False)
fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
fruits.sort()
5.1.1 列表作为栈使用
列表方法使得列表作为堆栈非常容易,最后一个插入,最先取出(“后进先出”)。要添加一个元素到堆栈的顶端,使用 append() 。要从堆栈顶部取出一个元素,使用 pop() ,不用指定索引
>>>stack = [3, 4, 5]
>>>stack.append(6)
>>>stack.append(7)
5.1.2. 列表作为队列使用
列表也可以用作队列,其中先添加的元素被最先取出 (“先进先出”);然而列表用作这个目的相当低效。因为在列表的末尾添加和弹出元素非常快,但是在列表的开头插入或弹出元素却很慢 (因为所有的其他元素都必须移动一位)。
若要实现一个队列, collections.deque
被设计用于快速地从两端操作。例如
>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry") # Terry arrives
>>> queue.append("Graham") # Graham arrives
>>> queue.popleft() # The first to arrive now leaves
'Eric'
>>> queue.popleft() # The second to arrive now leaves
'John'
>>> queue # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])
5.1.3. 列表推导式
>>> [(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
列表推导式可以使用复杂的表达式和嵌套函数
>>> from math import pi
>>> [str(round(pi, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']
5.1.4. 嵌套的列表推导式
考虑下面这个 3x4的矩阵,它由3个长度为4的列表组成
>>> matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
#下面的列表推导式将交换其行和列
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
实际应用中,你应该会更喜欢使用内置函数去组成复杂的流程语句。
>>> list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
5.2. del 语句
有一种方式可以从列表按照给定的索引而不是值来移除一个元素: 那就是 del
语句。 它不同于会返回一个值的 pop()
方法。 del
语句也可以用来从列表中移除切片或者清空整个列表(我们之前用过的方式是将一个空列表赋值给指定的切片)。 例如:
>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>> del a[:]
>>> a
[]
del a
5.3. 元组和序列
一个元组由几个被逗号隔开的值组成,例如
>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
虽然元组可能看起来与列表很像,但它们通常是在不同的场景被使用,并且有着不同的用途。元组是 immutable (不可变的),其序列通常包含不同种类的元素,并且通过解包(这一节下面会解释)或者索引来访问(如果是 namedtuples
的话甚至还可以通过属性访问)。列表是 mutable (可变的),并且列表中的元素一般是同种类型的,并且通过迭代访问。
>>> empty = ()
>>> singleton = 'hello', # <-- note trailing comma
>>> len(empty)
0
>>> len(singleton)
1
>>> singleton
('hello',)
>>>t = 12345, 54321, 'hello!'
>>> x, y, z = t
5.4. 集合
Python也包含有 集合 类型。集合是由不重复元素组成的无序的集。它的基本用法包括成员检测和消除重复元素。集合对象也支持像 联合,交集,差集,对称差分等数学运算。
花括号或 set()
函数可以用来创建集合。注意:要创建一个空集合你只能用 set()
而不能用 {}
,因为后者是创建一个空字典,这种数据结构我们会在下一节进行讨论
>>>set("hkjh")
Out[100]: {'h', 'j', 'k'}
>>>{"hkjh"}
Out[101]: {'hkjh'}
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b # letters in a or b or both
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b # letters in both a and b
{'a', 'c'}
>>> a ^ b # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}
类似于 列表推导式,集合也支持推导式形式
>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}
5.5. 字典
dict()
构造函数可以直接从键值对序列里创建字典。
此外,字典推导式可以从任意的键值表达式中创建字典
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
5.6. 循环的技巧
当在字典中循环时,用 items() 方法可将关键字和对应的值同时取出
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
... print(k, v)
...
gallahad the pure
robin the brave
当在序列中循环时,用 enumerate()
函数可以将索引位置和其对应的值同时取出
>>> for i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
0 tic
1 tac
2 toe
当同时在两个或更多序列中循环时,可以用 zip()
函数将其内元素一一匹配。
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
... print('What is your {0}? It is {1}.'.format(q, a))
...
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favorite color? It is blue.
当逆向循环一个序列时,先正向定位序列,然后调用 reversed()
函数
>>> for i in reversed(range(1, 10, 2)):
... print(i)
...
9
7
5
3
1
如果要按某个指定顺序循环一个序列,可以用 sorted()
函数,它可以在不改动原序列的基础上返回一个新的排好序的序列
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
... print(f)
...
apple
banana
orange
pear
有时可能会想在循环时修改列表内容,一般来说改为创建一个新列表是比较简单且安全的
>>> import math
>>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
>>> filtered_data = []
>>> for value in raw_data:
... if not math.isnan(value):
... filtered_data.append(value)
...
>>> filtered_data
[56.2, 51.7, 55.3, 52.5, 47.8]
6. 模块
模块是一个包含Python定义和语句的文件。文件名就是模块名后跟文件后缀 .py 。在一个模块内部,模块名(作为一个字符串)可以通过全局变量 name 的值获得。例如,使用你最喜爱的文本编辑器在当前目录下创建一个名为 fibo.py 的文件, 文件中含有以下内容:
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
>>>import fibo
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
6.1. 有关模块的更多信息
模块可以导入其它模块。习惯上但不要求把所有 import
语句放在模块(或脚本)的开头。被导入的模块名存放在调入模块的全局符号表中。如下:
from fibo import fib
from fibo import fib, fib2
from fibo import * ###不推荐,代码可读性下降
import fibo as fib
from fibo import fib as fibonacci
6.1.1. 以脚本的方式执行模块
当你用下面方式运行一个Python模块:
python fibo.py <arguments>
模块里的代码会被执行,就好像你导入了模块一样,但是 name 被赋值为 "main"。 这意味着通过在你的模块末尾添加这些代码:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
6.1.2. 模块搜索路径
查看sys.path.sys.path
初始有这些目录地址:
- 包含输入脚本的目录(或者未指定文件时的当前目录)。
-
PYTHONPATH
(一个包含目录名称的列表,它和shell变量PATH
有一样的语法)。 - 取决于安装的默认设置
6.1.3. “编译过的”Python文件
为了加速模块载入,Python在 pycache 目录里缓存了每个模块的编译后版本,名称为 module.version.pyc ,其中名称中的版本字段对编译文件的格式进行编码; 它一般使用Python版本号。例如,在CPython版本3.3中,spam.py的编译版本将被缓存为 pycache/spam.cpython-33.pyc。此命名约定允许来自不同发行版和不同版本的Python的已编译模块共存。
给专业人士的一些小建议:
- 你可以在Python命令中使用
-O
或者-OO
开关, 以减小编译后模块的大小。-O
开关去除断言语句,-OO
开关同时去除断言语句和 doc 字符串。由于有些程序可能依赖于这些,你应当只在清楚自己在做什么时才使用这个选项。“优化过的”模块有一个opt-
标签并且通常小些。将来的发行版本或许会更改优化的效果。 - 一个从
.pyc
文件读出的程序并不会比它从.py
读出时运行的更快,.pyc
文件唯一快的地方在于载入速度。 -
compileall
模块可以为一个目录下的所有模块创建.pyc文件。 - 关于这个过程,PEP 3147 中有更多细节,包括一个决策流程图。
6.2. 标准模块
一个特别值得注意的模块 sys
,它被内嵌到每一个Python解释器中。变量 sys.ps1
和 sys.ps2
定义用作主要和辅助提示的字符串:【主要在交互模式时候进行定义】
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>
sys.path 变量是一个字符串列表,用于确定解释器的模块搜索路径。你可以使用标准列表操作对其进行修改:
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
6.3. dir()
函数
内置函数 dir()
用于查找模块定义的名称。 它返回一个排序过的字符串列表:
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
如果没有参数,dir()
会列出你当前定义的名称:
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
注意:它列出所有类型的名称:变量,模块,函数,等等。
dir()
不会列出内置函数和变量的名称。如果你想要这些,它们的定义是在标准模块 builtins
中:
>>> import builtins
>>> dir(builtins)
8.错误与异常
- try/except/else/finally
try:
main-action
except Exception1:
handler1
except Exception2:
hanlder2
...
else:
else-Block
finally:
finally-block
``
打印异常
try:
print(2/'0')
except (ZeroDivisionError,Exception) as e:
# unsupported operand type(s) for /: 'int' and 'str'
print(e)
自定义异常:
![image.png](https://upload-images.jianshu.io/upload_images/9589088-b74f77a4270ec129.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
9.类
9.2. Python 作用域和命名空间
关于命名空间的重要一点是,不同命名空间中的名称之间绝对没有关系;例如,两个不同的模块都可以定义一个 maximize 函数而不会产生混淆 --- 模块的用户必须在其前面加上模块名称。
我把任何跟在一个点号之后的名称都称为
属性
属性可以是只读或者可写的。如果为后者,那么对属性的赋值是可行的。模块属性是可以写,你可以写出
modname.the_answer = 42
。可写的属性同样可以用del
语句删除。例如,del modname.the_answer
将会从名为modname
的对象中移除the_answer
属性。
第一,两者的功能不同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误(最上层的函数使用nonlocal修饰变量必定会报错)。
第二,两者使用的范围不同。global关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global修饰后也可以直接使用,而nonlocal关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误
9.3. 初探类
类对象支持两种操作:属性引用和实例化。
属性引用 使用 Python 中所有属性引用所使用的标准语法: obj.name。 有效的属性名称是类对象被创建时存在于类命名空间中的所有名称。 因此,如果类定义是这样的:
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
那么 MyClass.i
和MyClass.f
就是有效的属性引用,将分别返回一个整数和一个函数对象。 类属性也可以被赋值,因此可以通过赋值来更改 MyClass.i
的值。 __doc__
也是一个有效的属性,将返回所属类的文档字符串: "A simple example class"
。
9.4. 补充说明
- 任何一个作为类属性的函数都为该类的实例定义了一个相应方法。 函数定义的文本并非必须包含于类定义之内:将一个函数对象赋值给一个局部变量也是可以的。 例如:
# Function defined outside the class
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return 'hello world'
h = g
现在 f, g 和 h 都是 C 类的引用函数对象的属性,因而它们就都是 C 的实例的方法 --- 其中 h 完全等同于 g。 但请注意,本示例的做法通常只会令程序的阅读者感到迷惑。
9.5. 继承
Python有两个内置函数可被用于继承机制:
- 使用
isinstance()
来检查一个实例的类型:isinstance(obj, int)
仅会在obj.__class__
为int
或某个派生自int
的类时为True
。 - 使用
issubclass()
来检查类的继承关系:issubclass(bool, int)
为True
,因为bool
是int
的子类。 但是,issubclass(float, int)
为False
,因为float
不是int
的子类。
9.6. 私有变量
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),因此存在对此种机制的有限支持,称为 名称改写。 任何形式为 __spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 _classname__spam,其中 classname 为去除了前缀下划线的当前类名称。 这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。
名称改写有助于让子类重载方法而不破坏类内方法调用。例如:
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # private copy of original update() method
class MappingSubclass(Mapping):
def update(self, keys, values):
# provides new signature for update()
# but does not break __init__()
for item in zip(keys, values):
self.items_list.append(item)
- 上面的示例即使在 MappingSubclass 引入了一个 __update 标识符的情况下也不会出错,因为它会在 Mapping 类中被替换为 _Mapping__update 而在 MappingSubclass 类中被替换为 _MappingSubclass__update。
9.7. 杂项说明
-有时会需要使用类似于 Pascal 的“record”或 C 的“struct”这样的数据类型,将一些命名数据项捆绑在一起。 这种情况适合定义一个空类:
class Employee:
pass
john = Employee() # Create an empty employee record
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
生成器;迭代器
10. 标准库简介
urllib整个模块分为urllib.request, urllib.parse, urllib.error。
10.1. 操作系统接口
os
模块提供了许多与操作系统交互的函数:
>>>> import os
>>> os.getcwd() # Return the current working directory
'C:\\Python37'
>>> os.chdir('/server/accesslogs') # Change current working directory
>>> os.system('mkdir today') # Run the command mkdir in the system shell
一定要使用 import os
而不是 from os import *
。这将避免内建的 open()
函数被 os.open()
隐式替换掉,它们的使用方式大不相同。
内置的 dir()
和 help()
函数可用作交互式辅助工具,用于处理大型模块,如 os
>>>> import os
>>> dir(os)
<returns a list of all module functions>
>>> help(os)
<returns an extensive manual page created from the module's docstrings>
对于日常文件和目录管理任务, shutil
模块提供了更易于使用的更高级别的接口:
>>>> import shutil
>>> shutil.copyfile('data.db', 'archive.db')
'archive.db'
>>> shutil.move('/build/executables', 'installdir')
'installdir'
10.2. 文件通配符
glob
模块提供了一个在目录中使用通配符搜索创建文件列表的函数:
>>>> import glob
>>> glob.glob('*.py')
['primes.py', 'random.py', 'quote.py']
10.3. 命令行参数
通用实用程序脚本通常需要处理命令行参数。这些参数作为列表存储在 sys
模块的 argv 属性中。例如,以下输出来自在命令行运行 python demo.py one two three
>>>> import sys
>>> print(sys.argv)
['demo.py', 'one', 'two', 'three']
getopt
模块使用Unix getopt()
函数的约定来处理 sys.argv 。 argparse
模块提供了更强大,更灵活的命令行参数处理。
10.4. 错误输出重定向和程序终止
sys
模块还具有 stdin , stdout 和 stderr 的属性。后者对于发出警告和错误消息非常有用,即使在 stdout被重定向后也可以看到它们:
>>>> sys.stderr.write('Warning, log file not found starting a new one\n')
Warning, log file not found starting a new one
终止脚本的最直接方法是使用 sys.exit()
。
10.5. 字符串模式匹配
re
模块为高级字符串处理提供正则表达式工具。对于复杂的匹配和操作,正则表达式提供简洁,优化的解决方案:
>>>> import re
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'
当只需要简单的功能时,首选字符串方法因为它们更容易阅读和调试:
'tea for two'
10.6. 数学
math
模块提供对浮点数学的底层C库函数的访问:
>>> math.cos(math.pi / 4)
0.70710678118654757
>>> math.log(1024, 2)
10.0
random
模块提供了进行随机选择的工具:
>>>> import random
>>> random.choice(['apple', 'pear', 'banana'])
'apple'
>>> random.sample(range(100), 10) # sampling without replacement
[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
>>> random.random() # random float
0.17970987693706186
>>> random.randrange(6) # random integer chosen from range(6)
4
statistics
模块计算数值数据的基本统计属性(均值,中位数,方差等):
>>>> import statistics
>>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
>>> statistics.mean(data)
1.6071428571428572
>>> statistics.median(data)
1.25
>>> statistics.variance(data)
1.3720238095238095
SciPy项目 <https://scipy.org> 有许多其他模块用于数值计算。
10.7. 互联网访问
有许多模块可用于访问互联网和处理互联网协议。其中两个最简单的 urllib.request
用于从URL检索数据,以及 smtplib
用于发送邮件:
>>>> from urllib.request import urlopen
>>> with urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl') as response:
... for line in response:
... line = line.decode('utf-8') # Decoding the binary data to text.
... if 'EST' in line or 'EDT' in line: # look for Eastern Time
... print(line)
<BR>Nov. 25, 09:43:32 PM EST
>>> import smtplib
>>> server = smtplib.SMTP('localhost')
>>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
... """To: jcaesar@example.org
... From: soothsayer@example.org
...
... Beware the Ides of March.
... """)
>>> server.quit()
(请注意,第二个示例需要在localhost上运行的邮件服务器。)
10.8. 日期和时间
datetime
模块提供了以简单和复杂的方式操作日期和时间的类。虽然支持日期和时间算法,但实现的重点是有效的成员提取以进行输出格式化和操作。该模块还支持可感知时区的对象。
>>>> # dates are easily constructed and formatted
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2003, 12, 2)
>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
'12-02-03\. 02 Dec 2003 is a Tuesday on the 02 day of December.'
>>> # dates support calendar arithmetic
>>> birthday = date(1964, 7, 31)
>>> age = now - birthday
>>> age.days
14368
10.9. 数据压缩
常见的数据存档和压缩格式由模块直接支持,包括:zlib
, gzip
, bz2
, lzma
, zipfile
和 tarfile
。:
>>>> import zlib
>>> s = b'witch which has which witches wrist watch'
>>> len(s)
41
>>> t = zlib.compress(s)
>>> len(t)
37
>>> zlib.decompress(t)
b'witch which has which witches wrist watch'
>>> zlib.crc32(s)
226805979
10.10. 性能测量
一些Python用户对了解同一问题的不同方法的相对性能产生了浓厚的兴趣。 Python提供了一种可以立即回答这些问题的测量工具。
例如,元组封包和拆包功能相比传统的交换参数可能更具吸引力。timeit
模块可以快速演示在运行效率方面一定的优势:
>>>> from timeit import Timer
>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
0.57535828626024577
>>> Timer('a,b = b,a', 'a=1; b=2').timeit()
0.54962537085770791
与 timeit
的精细粒度级别相反, profile
和 pstats
模块提供了用于在较大的代码块中识别时间关键部分的工具。
10.11. 质量控制
开发高质量软件的一种方法是在开发过程中为每个函数编写测试,并在开发过程中经常运行这些测试。
doctest
模块提供了一个工具,用于扫描模块并验证程序文档字符串中嵌入的测试。测试构造就像将典型调用及其结果剪切并粘贴到文档字符串一样简单。这通过向用户提供示例来改进文档,并且它允许doctest模块确保代码保持对文档的真实:
>>> print(average([20, 30, 70]))
40.0
"""
return sum(values) / len(values)
import doctest
doctest.testmod() # automatically validate the embedded tests
unittest
模块不像 doctest
模块那样易于使用,但它允许在一个单独的文件中维护更全面的测试集:
>import unittest
class TestStatisticalFunctions(unittest.TestCase):
def test_average(self):
self.assertEqual(average([20, 30, 70]), 40.0)
self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
with self.assertRaises(ZeroDivisionError):
average([])
with self.assertRaises(TypeError):
average(20, 30, 70)
unittest.main() # Calling from the command line invokes all tests