re 模块
正则
- 最短匹配模式(非贪婪)
- 多行匹配(
re.compile(r'/\*(.*?)\*/', re.DOTALL)或者(?:.|\n)指定一个非捕获组)
查找
如果想匹配的是字面字符串,那么通常只需要调用基本字符串方法就行, 比如 str.find() , str.endswith() , str.startswith() 。
复杂的匹配需要使用正则表达式和 re 模块。
>>> text1 = '11/27/2012'
>>> text2 = 'Nov 27, 2012'
>>>
>>> import re
>>> # Simple matching: \d+ means match one or more digits
>>> if re.match(r'\d+/\d+/\d+', text1):
... print('yes')
... else:
... print('no')
...
如果想使用同一个模式去做多次匹配,你应该先将模式字符串预编译为模式对象。比如:
>>> datepat = re.compile(r'\d+/\d+/\d+')
>>> if datepat.match(text1):
... print('yes')
... else:
... print('no')
...
match() 总是从字符串开始去匹配,如果你想查找字符串任意部分的模式出现位置, 使用 findall() 方法去代替。
在定义正则式的时候,通常会利用括号去捕获分组。
>>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> text
'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> datepat.findall(text)
[('11', '27', '2012'), ('3', '13', '2013')]
>>> for month, day, year in datepat.findall(text):
... print('{}-{}-{}'.format(year, month, day))
...
2012-11-27
2013-3-13
>>>
findall() 方法会搜索文本并以列表形式返回所有的匹配。 如果想以迭代方式返回匹配,可以使用 finditer() 方法来代替,比如:
>>> for m in datepat.finditer(text):
... print(m.groups())
...
('11', '27', '2012')
('3', '13', '2013')
>>>
替换
对于简单的字面模式,直接使用 str.replace() 方法即可,对于复杂的模式,使用 re 模块中的 sub() 函数。
>>> text = 'UPPER PYTHON, lower python, Mixed Python'
>>> re.findall('python', text, flags=re.IGNORECASE)
['PYTHON', 'python', 'Python']
>>> re.sub('python', 'snake', text, flags=re.IGNORECASE)
'UPPER snake, lower snake, Mixed snake'
>>>
上面例子有个缺陷,替换字符串并不会自动跟被匹配字符串的大小写保持一致。
def matchcase(word):
def replace(m):
text = m.group()
if text.isupper():
return word.upper()
elif text.islower():
return word.lower()
elif text[0].isupper():
return word.capitalize()
else:
return word
return replace
>>> re.sub('python', matchcase('snake'), text, flags=re.IGNORECASE)
'UPPER SNAKE, lower snake, Mixed Snake'
>>>
matchcase('snake') 返回了一个回调函数(参数必须是 match 对象),前面一节提到过, sub() 函数除了接受替换字符串外,还能接受一个回调函数。
对于一般的忽略大小写的匹配操作,简单的传递一个 re.IGNORECASE 标志参数就已经足够了。但是需要注意的是,这个对于某些需要大小写转换的 Unicode 匹配可能还不够。
在正则式中使用 Unicode
默认情况下re模块已经对一些 Unicode 字符类有了基本的支持。 比如,\\d 已经匹配任意的 unicode 数字字符了。
>>> import re
>>> num = re.compile('\d+')
>>> # ASCII digits
>>> num.match('123')
<_sre.SRE_Match object at 0x1007d9ed0>
>>> # Arabic digits
>>> num.match('\u0661\u0662\u0663')
<_sre.SRE_Match object at 0x101234030>
>>>
混合使用Unicode和正则表达式,最好还是使用增强的第三方库,比如: regex
字符串令牌解析
有一个字符串,想从左至右将其解析为一个令牌流。
对于复杂的语法,最好是选择某个解析工具比如 PyParsing 或者是 PLY。
unicodedata 模块
标准化对于任何需要以一致的方式处理Unicode文本的程序都是非常重要的,当处理来自用户输入的字符串而你很难去控制编码的时候尤其如此。
>>> s1 = 'Spicy Jalape\u00f1o'
>>> s2 = 'Spicy Jalapen\u0303o'
>>> s1
'Spicy Jalapeño'
>>> s2
'Spicy Jalapeño'
>>> s1 == s2
False
>>> len(s1)
14
>>> len(s2)
15
>>>
>>> import unicodedata
>>> t1 = unicodedata.normalize('NFC', s1)
>>> t2 = unicodedata.normalize('NFC', s2)
>>> t1 == t2
True
>>> print(ascii(t1))
'Spicy Jalape\xf1o'
>>> t3 = unicodedata.normalize('NFD', s1)
>>> t4 = unicodedata.normalize('NFD', s2)
>>> t3 == t4
True
>>> print(ascii(t3))
'Spicy Jalapen\u0303o'
>>>
>>> t1 = unicodedata.normalize('NFD', s1)
>>> ''.join(c for c in t1 if not unicodedata.combining(c))
'Spicy Jalapeno'
>>>
collections 模块
deque()
在迭代操作或者其他操作的时候,只保留最后有限几个元素的历史记录。deque(maxlen=N)构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候, 最老的元素会自动被移除掉。
在队列两端插入或删除元素时间复杂度都是O(1),区别于列表,在列表的开头插入或删除元素的时间复杂度为O(N)。
在写查询元素的代码时,通常会使用包含yield表达式的生成器函数,这样可以将搜索过程代码和使用搜索结果代码解耦。
from collections import deque
def my_search(lines, pattern, history=5):
previous_lines = deque(maxlen=history)
for line in lines:
if pattern in line:
yield line, previous_lines
previous_lines.append(line)
# Example use on a file
if __name__ == '__main__':
with open(r'../../cookbook/somefile.txt') as f:
for line, prevlines in my_search(f, 'python', 5):
for pline in prevlines:
print(pline, end='')
print(line, end='')
print('-' * 20)
defaultdict()
一个字典就是一个键对应一个单值的映射。如果你想要一个键映射多个值,就需要将这多个值放到另外的容器中,比如列表或者集合里面。
可以很方便的使用collections模块中的defaultdict来构造这样的字典。
from collections import defaultdict
d = defaultdict(list)
d['a'].append(1)
d['a'].append(2)
d['b'].append(4)
d = defaultdict(set)
d['a'].add(1)
d['a'].add(2)
d['b'].add(4)
需要注意的是, defaultdict 会自动为将要访问的键(就算目前字典中并不存在这样的键)创建映射实体。
OrderedDict()
创建一个字典,并且在迭代或序列化这个字典的时候能够控制元素的顺序。
为了能控制一个字典中元素的顺序,可以使用collections模块中的OrderedDict类。在迭代操作的时候它会保持元素被插入时的顺序
from collections import OrderedDict
d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spam'] = 3
d['grok'] = 4
# Outputs "foo 1", "bar 2", "spam 3", "grok 4"
for key in d:
print(key, d[key])
OrderedDict 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候, 它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会改变键的顺序。
需要注意的是,一个 OrderedDict 的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。 所以如果你要构建一个需要大量 OrderedDict 实例的数据结构的时候(比如读取 100,000 行 CSV 数据到一个 OrderedDict 列表中去), 那么你就得仔细权衡一下是否使用 OrderedDict 带来的好处要大过额外内存消耗的影响。
Counter()
找出一个序列中出现次数最多的元素
words = [
'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',
'eyes', "don't", 'look', 'around', 'the', 'eyes', 'look', 'into',
'my', 'eyes', "you're", 'under'
]
from collections import Counter
word_counts = Counter(words)
# 出现频率最高的3个单词
top_three = word_counts.most_common(3)
print(top_three)
# Outputs [('eyes', 8), ('the', 5), ('look', 4)]
namedtuple()
collections.namedtuple()这个函数实际上是一个返回 Python 中标准元组类型子类的一个工厂方法。
传递一个类型名和你需要的字段给它,然后它就会返回一个类,可以初始化这个类,为定义的字段传递值等。
>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriber(addr='jonesy@example.com', joined='2012-10-19')
>>> sub.addr
'jonesy@example.com'
>>> sub.joined
'2012-10-19'
>>>
尽管 namedtuple 的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组操作,比如索引和解压。 比如:
>>> len(sub)
2
>>> addr, joined = sub
>>> addr
'jonesy@example.com'
>>> joined
'2012-10-19'
>>>
命名元组的一个主要用途是将代码从下标操作中解脱出来。 因此,在数据库调用中返回了一个很大的元组列表的情况下,使用命名元组增删就会很方便。
def compute_cost(records):
total = 0.0
for rec in records:
total += rec[1] * rec[2]
return total
下标操作通常会让代码表意不清晰,并且非常依赖记录的结构。 下面是使用命名元组的版本:
from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def compute_cost(records):
total = 0.0
for rec in records:
s = Stock(*rec)
total += s.shares * s.price
return total
命名元组另一个用途就是作为字典的替代,因为字典存储需要更多的内存空间。 如果需要构建一个非常大的包含字典的数据结构,那么使用命名元组会更加高效。 但是需要注意的是,不像字典那样,一个命名元组是不可更改的。比如:
>>> s = Stock('ACME', 100, 123.45)
>>> s
Stock(name='ACME', shares=100, price=123.45)
>>> s.shares = 75
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>>
如果真的需要改变属性的值,那么可以使用命名元组实例的 _replace() 方法, 它会创建一个全新的命名元组并将对应的字段用新的值取代。比如:
>>> s = s._replace(shares=75)
>>> s
Stock(name='ACME', shares=75, price=123.45)
>>>
ChainMap
现在有多个字典或者映射,将它们从逻辑上合并为一个单一的映射后执行某些操作,比如查找值或者检查某些键是否存在。
a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }
from collections import ChainMap
c = ChainMap(a,b)
print(c['x']) # Outputs 1 (from a)
print(c['y']) # Outputs 2 (from b)
print(c['z']) # Outputs 3 (from a)
一个 ChainMap 接受多个字典并将它们在逻辑上变为一个字典。 然后,这些字典并不是真的合并在一起了, ChainMap 类只是在内部创建了一个容纳这些字典的列表 并重新定义了一些常见的字典操作来遍历这个列表。大部分字典操作都是可以正常使用。
与 update() 不同的是:使用 update 如果原字典做了更新,这种改变不会反应到新的合并字典中去。ChainMap 使用原来的字典,它自己不创建新的字典,所以会随之改变。
heapq 模块
从一个集合中获得最大或者最小的 N 个元素列表。
heapq 模块有两个函数:nlargest()和nsmallest()可以完美解决这个问题。
import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]
在底层实现里面,首先会先将集合数据进行堆排序后放入一个列表中。
堆数据结构最重要的特征是heap[0]永远是最小的元素。并且剩余的元素可以很容易的通过调用heapq.heappop()方法得到, 该方法会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素(这种操作时间复杂度仅仅是O(log N),N是堆大小)。
>>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
>>> import heapq
>>> heap = list(nums)
>>> heapq.heapify(heap)
>>> heap
[-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8]
>>>
当要查找的元素个数相对比较小的时候,函数 nlargest() 和 nsmallest() 是很合适的。 如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用 min() 和 max() 函数会更快些。 类似的,如果 N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点 ( sorted(items)[:N] 或者是 sorted(items)[-N:] )。 需要在正确场合使用函数 nlargest() 和 nsmallest() 才能发挥它们的优势 (如果 N 快接近集合大小了,那么使用排序操作会更好些)。
顺序迭代合并后的排序迭代对象
有一系列排序序列,想将它们合并后得到一个排序序列并在上面迭代遍历。
>>> import heapq
>>> a = [1, 4, 7, 10]
>>> b = [2, 5, 6, 11]
>>> for c in heapq.merge(a, b):
... print(c)
...
1
2
4
5
6
7
10
11
heapq.merge() 需要所有输入序列必须是排过序的。 特别的,它并不会预先读取所有数据到堆栈中或者预先排序,也不会对输入做任何的排序检测。它仅仅是检查所有序列的开始部分并返回最小的那个,这个过程一直会持续直到所有输入序列中的元素都被遍历完。
operator 模块
itemgetter()
根据某个或某几个字典字段来排序这个列表,通过使用operator模块的itemgetter函数,可以非常容易的排序这样的数据结构:
rows = [
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]
from operator import itemgetter
rows_by_fname = sorted(rows, key=itemgetter('fname'))
rows_by_uid = sorted(rows, key=itemgetter('uid'))
itemgetter()有时候也可以用lambda表达式代替,比如:
rows_by_fname = sorted(rows, key=lambda r: r['fname'])
rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
使用itemgetter()方式会运行的稍微快点。因此,如果你对性能要求比较高的话就使用itemgetter()方式。
>>> min(rows, key=itemgetter('uid'))
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001}
>>> max(rows, key=itemgetter('uid'))
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
>>>
attrgetter()
排序类型相同的对象,但是他们不支持原生的比较操作。
内置的 sorted() 函数有一个关键字参数 key ,可以传入一个 callable 对象给它, 这个 callable 对象对每个传入的对象返回一个值,这个值会被 sorted 用来排序这些对象。 比如,如果你在应用程序里面有一个 User 实例序列,并且你希望通过他们的 user_id 属性进行排序, 你可以提供一个以 User 实例作为输入并输出对应 user_id 值的 callable 对象。
class User:
def __init__(self, user_id):
self.user_id = user_id
def __repr__(self):
return 'User({})'.format(self.user_id)
sorted(users, key=lambda u: u.user_id) # [User(3), User(23), User(99)]
from operator import attrgetter
sorted(users, key=attrgetter('user_id')) # [User(3), User(23), User(99)]
itertools 模块
islice()
用于 迭代器和生成器 上的切片操作。
dropwhile()
用于丢弃一个可迭代对象前面的元素。
permutations()/combinations()/combinations_with_replacement()
排列组合的迭代(迭代遍历一个集合中元素的所有可能的排列或组合)。
zip_longest()
同时迭代多个序列,并且对其长度。
chain()
合并多个集合,创建迭代器。
groupby()
有一个字典或者实例的序列,然后你想根据某个特定的字段比如 date 来分组迭代访问。
itertools.groupby() 函数对于这样的数据分组操作非常实用。
rows = [
{'address': '5412 N CLARK', 'date': '07/01/2012'},
{'address': '5148 N CLARK', 'date': '07/04/2012'},
{'address': '5800 E 58TH', 'date': '07/02/2012'},
{'address': '2122 N CLARK', 'date': '07/03/2012'},
{'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
{'address': '1060 W ADDISON', 'date': '07/02/2012'},
{'address': '4801 N BROADWAY', 'date': '07/01/2012'},
{'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
]
from operator import itemgetter
from itertools import groupby
# Sort by the desired field first
rows.sort(key=itemgetter('date'))
# Iterate in groups
for date, items in groupby(rows, key=itemgetter('date')):
print(date)
for i in items:
print(' ', i)
运行结果:
07/01/2012
{'date': '07/01/2012', 'address': '5412 N CLARK'}
{'date': '07/01/2012', 'address': '4801 N BROADWAY'}
07/02/2012
{'date': '07/02/2012', 'address': '5800 E 58TH'}
{'date': '07/02/2012', 'address': '5645 N RAVENSWOOD'}
{'date': '07/02/2012', 'address': '1060 W ADDISON'}
07/03/2012
{'date': '07/03/2012', 'address': '2122 N CLARK'}
07/04/2012
{'date': '07/04/2012', 'address': '5148 N CLARK'}
{'date': '07/04/2012', 'address': '1039 W GRANVILLE'}
compress()
它以一个 iterable 对象和一个相对应的 Boolean 选择器序列作为输入参数。 然后输出 iterable 对象中对应选择器为 True 的元素。 当需要用另外一个相关联的序列来过滤某个序列的时候,这个函数是非常有用的。 比如:
addresses = [
'5412 N CLARK',
'5148 N CLARK',
'5800 E 58TH',
'2122 N CLARK',
'5645 N RAVENSWOOD',
'1060 W ADDISON',
'4801 N BROADWAY',
'1039 W GRANVILLE',
]
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
将那些对应 count 值大于5的地址全部输出,可以这样做:
>>> from itertools import compress
>>> more5 = [n > 5 for n in counts]
>>> more5
[False, False, True, False, False, True, True, False]
>>> list(compress(addresses, more5))
['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']
>>>
这里的关键点在于先创建一个 Boolean 序列,指示哪些元素符合条件。 然后 compress() 函数根据这个序列去选择输出对应位置为 True 的元素。
和 filter() 函数类似, compress() 也是返回的一个迭代器。因此,如果你需要得到一个列表, 那么你需要使用 list() 来将结果转换为列表类型。
logging 模块
time 模块
import time
# 当前时间戳(秒)
ts = time.time()
print("当前时间戳:", ts, type(ts))
# 输出示例: 1681440000.123456 <class 'float'>
# 时间戳 -> 本地时间元组
local = time.localtime(ts)
print("本地时间元组:", local, type(local))
# time.struct_time(tm_year=..., ...) <class 'time.struct_time'>
# 时间元组 -> 字符串
str_time = time.strftime("%Y-%m-%d %H:%M:%S", local)
print("格式化时间字符串:", str_time, type(str_time))
# '2025-04-10 15:30:45' <class 'str'>
# 字符串 -> 时间元组
parsed = time.strptime("2025-01-01 12:00:00", "%Y-%m-%d %H:%M:%S")
print("解析后的时间元组:", parsed, type(parsed))
# time.struct_time(tm_year=2025, ...) <class 'time.struct_time'>
# 时间元组 -> 时间戳
ts_from_struct = time.mktime(parsed)
print("从结构体得到时间戳:", ts_from_struct, type(ts_from_struct))
# 1735723200.0 <class 'float'>
datetime 模块
from datetime import datetime, timedelta
# 当前时间
now = datetime.now()
print("当前 datetime:", now, type(now))
# 2025-04-10 15:30:45.123456 <class 'datetime.datetime'>
# 自定义时间
d = datetime(2024, 12, 31, 23, 59, 59)
print("自定义 datetime:", d, type(d))
# 2024-12-31 23:59:59 <class 'datetime.datetime'>
# datetime -> 字符串
formatted = d.strftime("%Y/%m/%d %H:%M")
print("格式化:", formatted, type(formatted))
# '2024/12/31 23:59' <class 'str'>
# 字符串 -> datetime
parsed_dt = datetime.strptime("2025-03-15 08:30", "%Y-%m-%d %H:%M")
print("字符串解析为 datetime:", parsed_dt, type(parsed_dt))
# 2025-03-15 08:30:00 <class 'datetime.datetime'>
# 获取时间差
delta = now - parsed_dt
print("时间差:", delta, type(delta))
# datetime.timedelta(days=..., seconds=...) <class 'datetime.timedelta'>
print("差多少天:", delta.days, type(delta.days))
# 26 <class 'int'>
print("差多少秒:", delta.total_seconds(), type(delta.total_seconds()))
# 2276400.0 <class 'float'>
# 加减时间
future = now + timedelta(days=7)
print("7天后:", future, type(future))
# <class 'datetime.datetime'>
past = now - timedelta(hours=3)
print("3小时前:", past, type(past))
# <class 'datetime.datetime'>
# datetime -> 时间戳
timestamp = now.timestamp()
print("当前 datetime 转时间戳:", timestamp, type(timestamp))
# 1681440000.0 <class 'float'>
# 时间戳 -> datetime
from_ts = datetime.fromtimestamp(timestamp)
print("时间戳转 datetime:", from_ts, type(from_ts))
# <class 'datetime.datetime'>
# ISO 格式时间(标准格式)
iso_str = now.isoformat()
print("ISO 格式:", iso_str, type(iso_str))
# '2025-04-10T15:30:45.123456' <class 'str'>
# 获取当前 UTC 时间
utc_now = datetime.utcnow()
print("当前 UTC 时间:", utc_now, type(utc_now))
# <class 'datetime.datetime'>
# 替换 datetime 中的部分值
new_time = now.replace(hour=0, minute=0)
print("替换后的时间:", new_time, type(new_time))
# <class 'datetime.datetime'>
| 内容 | 示例输出类型 |
|---|---|
| 时间戳 | <class 'float'> |
| 时间元组 | <class 'time.struct_time'> |
| 格式化字符串时间 | <class 'str'> |
datetime 对象 |
<class 'datetime.datetime'> |
| 时间差对象 | <class 'datetime.timedelta'> |
total_seconds() |
<class 'float'> |
days 属性 |
<class 'int'> |
time 和 datetime 对比
| 功能 | time 模块 |
datetime 模块 |
|---|---|---|
| 时间戳操作 | ✅ time.time() |
✅ datetime.timestamp() |
| 字符串格式化 | ✅ strftime / strptime |
✅ 同样支持 |
| 时间差计算 | ❌(需手动计算) | ✅ datetime - datetime |
| 加减时间 | ❌(需要封装) | ✅ 使用 timedelta |
| 可读性 & OOP | 较底层 | 更直观、更强大 |
pytz 模块
对几乎所有涉及到时区的问题,都应该使用 pytz 模块。这个包提供了Olson时区数据库, 它是时区信息的事实上的标准,在很多语言和操作系统里面都可以找到。
pytz 模块一个主要用途是将 datetime 库创建的简单日期对象本地化。 比如,下面如何表示一个芝加哥时间的示例:
>>> from datetime import datetime
>>> from pytz import timezone
>>> d = datetime(2012, 12, 21, 9, 30, 0)
>>> print(d)
2012-12-21 09:30:00
>>>
>>> # Localize the date for Chicago
>>> central = timezone('US/Central')
>>> loc_d = central.localize(d)
>>> print(loc_d)
2012-12-21 09:30:00-06:00
>>>
os 模块
八进制
>>> import os
>>> os.chmod('script.py', 0755)
File "<stdin>", line 1
os.chmod('script.py', 0755)
^
SyntaxError: invalid token
>>>
# 需确保八进制数的前缀是 0o
>>> os.chmod('script.py', 0o755)
>>>
operator 模块
math 模块
数学函数
import math
print(f"math.ceil(3.2) = {math.ceil(3.2)}") # 输出: math.ceil(3.2) = 4 (向上取整)
print(f"math.floor(3.8) = {math.floor(3.8)}") # 输出: math.floor(3.8) = 3 (向下取整)
print(f"math.trunc(-3.7) = {math.trunc(-3.7)}") # 输出: math.trunc(-3.7) = -3 (截断小数部分)
decimal 模块
精确计算浮点数(并能容忍一定的性能损耗)。
decimal 模块主要用在涉及到金融的领域。 在这类程序中,哪怕是一点小小的误差在计算过程中蔓延都是不允许的。 因此, decimal 模块为解决这类问题提供了方法。 当Python和数据库打交道的时候也通常会遇到 Decimal 对象,并且,通常也是在处理金融数据的时候。
>>> from decimal import Decimal
>>> a = Decimal('4.2')
>>> b = Decimal('2.1')
>>> a + b
Decimal('6.3')
>>> print(a + b)
6.3
>>> (a + b) == Decimal('6.3')
True
fractions 模块
fractions 模块可以被用来执行包含分数的数学运算。比如:
>>> from fractions import Fraction
>>> a = Fraction(5, 4)
>>> b = Fraction(7, 16)
>>> print(a + b)
27/16
>>> print(a * b)
35/64
>>> # Getting numerator/denominator
>>> c = a * b
>>> c.numerator
35
>>> c.denominator
64
>>> # Converting to a float
>>> float(c)
0.546875
>>> # Limiting the denominator of a value
>>> print(c.limit_denominator(8))
4/7
>>> # Converting a float to a fraction
>>> x = 3.75
>>> y = Fraction(*x.as_integer_ratio())
>>> y
Fraction(15, 4)
>>>
random 模块
random模块有大量的函数用来产生随机数和随机选择元素。 比如,要想从一个序列中随机的抽取一个元素,可以使用 random.choice() :
>>> import random
>>> values = [1, 2, 3, 4, 5, 6]
>>> random.choice(values)
2
>>> random.choice(values)
3
>>> random.choice(values)
1
>>> random.choice(values)
4
>>> random.choice(values)
6
>>>
为了提取出N个不同元素的样本用来做进一步的操作,可以使用 random.sample() :
>>> random.sample(values, 2)
[6, 2]
>>> random.sample(values, 2)
[4, 3]
>>> random.sample(values, 3)
[4, 3, 1]
>>> random.sample(values, 3)
[5, 4, 1]
>>>
打乱序列中元素的顺序,可以使用 random.shuffle() :
>>> random.shuffle(values)
>>> values
[2, 4, 6, 5, 3, 1]
>>> random.shuffle(values)
>>> values
[3, 5, 2, 1, 6, 4]
>>>
生成随机整数,请使用 random.randint() :
>>> random.randint(0,10)
2
>>> random.randint(0,10)
5
>>> random.randint(0,10)
0
>>> random.randint(0,10)
7
>>> random.randint(0,10)
10
>>> random.randint(0,10)
3
>>>
为了生成0到1范围内均匀分布的浮点数,使用 random.random() :
>>> random.random()
0.9406677561675867
>>> random.random()
0.133129581343897
>>> random.random()
0.4144991136919316
>>>
如果要获取N位随机位(二进制)的整数,使用 random.getrandbits() :
>>> random.getrandbits(200)
335837000776573622800628485064121869519521710558559406913275
>>>