重点总结
- Python 寻找变量的顺序:Python 内置 —> 当前目录 —> 第三方库,可手动添加自定义路径
- Python 寻找到同名的变量时,先匹先用
1 | 模块 Module
一个模块仅是一个 Python 文件,导入模块时用关键字 import
- 整体导入
import module
-
部分导入
from filename_without_py import target_file # target_file can be a file, a child package or defined object...
-
引入 + 别名
别名实际上相当于一个变量, 重新赋值变量时,确保没有使用其引入
import this_module_has_a_very_long_name as T
-
导入失败
>>> import script.zoo ModuleNotFoundError: No module named 'script.zoo';'script' is not a package
-
当前模块
当前模块名称可以通过全局变量
__name__
获取if __name__ == '__main__':
执行当前文件时运行的代码if __name__ == '__main__': print('aah') >>> python script.py 'aah'
💻dir()
>>> dir(sys) # 查看 sys 模块提供的名称
>>> dir() # 查看当前有那些非内置名称
# 可查看内置名称
>>> import builtins
>>> dir(builtins)
❓ 引入模块时,Python 从那些路径寻找
>>> import sys
>>> for place in sys.path:
print(place)
C:\python\3.11.2\Scripts\ipython3.exe
C:\python\3.11.2\python311.zip
C:\python\3.11.2\DLLs
C:\python\3.11.2\Lib
C:\python\3.11.2
# 该行空行表示当前目录
C:\python\3.11.2\Lib\site-packages
⚠️同名模块先匹先用,若在标准库路径前有其他路径具有同名模块,则直接使用
可以临时添加模块加载路径
import sys
sys.path.append('/ufs/guido/lib/python')
2 | 包 Packages
多个模块组成包
包的根目录下需创建一个__init__.py
文件(以此区分普通文件夹和 Python 包),该文件可为空
-
__all__
在
__init__.py
中定义的列表,可为空,用于定义开放对象,其元素将成为可以被 import 的名称避免用户通过类似
from this_pkg import *
这样的操作引入不需要的:# 假如用户在文件已经引入了 datetime from datetime import datetime # 但下列代码可能引入同名模块,导致用户的正确引用被覆盖 from this_pkg import *
-
包内引用,相对引用
假设目录结构如下:
Pack/ childA/ fileA-1.py childB/ fileB-1.py fileB-2.py
在文件 fileB-1.py 中可以:
from . import fileB-2 # 同级引入 from .. import childA # 引入上级 from ..childA import fileA-1 # 引入上级的某个文件
-
包外引用
__path__
一个包必须在
__init__.py
中定义__path__
,其值必须是包含str
类型的 iterable,可以为空,作用类似sys.path
适用情况:包内代码使用了其他包的某个文件,不定义则 python 不知道该文件在何处
-
名称空间包 namespace package
假设某个包内有 2 个
.py
模块,# 初始目录结构 pkg - mod_a.py - mod_b.py from pkg import mod_a, mod_b
但后期内容增加,希望将两个模块放置在不同目录下,可以这样操作:
# 调整之后的目录结构 A - pkg - mod_a.py B - pkg - mod_b.py from pkg import mod_a, mod_b
3 | .pyc 文件
为快速加载模块,Python 会对其预编译,编译文件放在 __pycache__
目录中,文件名为 module.version.pyc
⚠️.pyc 文件只是帮助加快加载,并不是比 .py文件加载快,标准库 compileall
可以编译某个路径的文件
version
:保证不同 Python 解释器实现生成的预编译文件不会互相覆盖,如mod.cpython-33.pyc
与 mod.jpython.pyc
何时重新编译?
Python 对比编译版本与源码的修改日期,已过期则重新编译
4 | 标准库
random
>>> import random
>>> random.choice(range(10))
2
Counter()
计数器,统计列表中某元素的出现次数,
from collections import Counter
c = Counter('letters')
# 逻辑相当于 {l:'letters'.count(l) for l in 'letters'}
>>> c
Counter({'e': 2, 't': 2, 'l': 1, 'r': 1, 's': 1})
>>> c.most_common(2) # 返回前两名
📋自 3.7, Counter
保留元素插入的顺序
📋 Counter 实例化的对象类似字典,可以直接增删 key 对应的计数
>>> c["a"] += 1
>>> c["a"]
2
itertools 库
该模块包含特殊的迭代器函数
import itertools
# 以下循环均省去print(i)
>>> for i in itertools.chain([1,2],['a','b']): # 按单个元素迭代所有可迭代的入参
1 2 a b
>>> for i in itertools.cycle([1,2]): # 无限循环迭代
1 2 1 2 1 2 1 2 ......
>>> for i in itertools.accumulate([1,2,3,4]): # 计算累加值
1 3 6 10
def func(x,y):
return a*b
>>> for i in itertools.accumulate([1,2,3,4], func): # 自插函数,计算累乘值
1 2 6 24
itemgetter()
可以取出设定的字段值,方便排序
rows = [ {"name": "C"},{"name": "A"}, {"name": "D"}, {"name": "B"}]
>>> sorted(rows, key=itemgetter("name"))
[{'name': 'A'}, {'name': 'B'}, {'name': 'C'}, {'name': 'D'}]
📋lambda 语句也可实现,但 itemgetter()
性能更好 😊
>>> sorted(rows, key=lambda x: x['name'])
attrgetter()
可取出对象属性值,比 lambda 性能更好
from operator import attrgetter
# class User:
# id: int
sorted(users, key=attrgetter("user_id"))
groupby()
传一个可迭代对象,返回一个分组值,及其对应的组数据
from itertools import groupby
rows = [
{"gender": "m","name": "John"},
{"gender": "f", "name": "My"},
{"gender": "m","name": "Bill"},
{"gender": "f", "name": "Cherry"}
]
rows.sort(key=itemgetter("gender"))
for v, items in groupby(rows, key=itemgetter('gender')):
print(v)
for i in items:
print(i)
# result:
f
{'gender': 'f', 'name': 'My'}
{'gender': 'f', 'name': 'Cherry'}
m
{'gender': 'm', 'name': 'John'}
{'gender': 'm', 'name': 'Bill'}
⚠️ 用前必须将可迭代入参排好顺序
compress(data, selctors)
传入一个可迭代对象,根据第二个参数布尔序列判断是否输出值
from itertools import compress
l = ['a', 'b', 'c']
bool_list = [True, False, True]
>>> list(compress(l, bool_list))
['a', 'c']
os
提供系统交换接口
import os
>>> os.getuid() # 用户 ID, Unix 系统可用
501
>>> os.getgid() # 组 ID, Unix 系统可用
20
>>> os.uname() # 获取系统信息,Unix 系统可用
posix.uname_result(sysname='Linux',
nodename='Dellana', release='5.15.90.1-microsoft-standard-WSL2',
version='#1 SMP Fri Jan 27 02:56:13 UTC 2023', machine='x86_64')
argparse
模块提供一种更复杂的机制处理命令行参数
🧲示例:可提取一个或多个文件名,并可选择要显示的行数
当在通过 python top.py --lines=5 alpha.txt beta.txt
在命令行运行时,该脚本会将 args.lines
设为 5
并将 args.filenames
设为 ['alpha.txt', 'beta.txt']
import argparse
parser = argparse.ArgumentParser(
prog='top',
description='Show top lines from each file')
parser.add_argument('filenames', nargs='+')
parser.add_argument('-l', '--lines', type=int, default=10)
args = parser.parse_args()
print(args)
数学相关
math
模块提供对浮点数学的底层C库函数的访问:
>>> import math
>>> 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 有许多其他模块用于数值计算
压缩相关
常见的数据存档和压缩格式由模块直接支持,包括: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
发送邮件
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()
解释器输出
pprint()
打印输出时增加可读性
from pprint import pprint
pprint(vars)
reprlib
返回字符串
import reprlib
reprlib.repr(set('supercalifragilisticexpialidocious'))
"{'a', 'c', 'd', 'e', 'f', 'g', ...}"
textwrap
折叠文本,与 HTML 中的类似
import textwrap
doc = """The wrap() method is just like fill() except that it returns
a list of strings instead of one big string with newlines to separate
the wrapped lines."""
>>> print(textwrap.fill(doc, width=40))
The wrap() method is just like fill()
except that it returns a list of strings
instead of one big string with newlines
to separate the wrapped lines.
locale
可处理与特定地域文化相关的数据格式
import locale
>>> locale.setlocale(locale.LC_ALL, 'English_United States.1252')
'English_United States.1252'
>>> locale.localeconv() # 获取本地配置
x = 1234567.8
>>> locale.format("%d", x, grouping=True)
'1,234,567'
>>> locale.format_string("%s%.*f", (conv['currency_symbol'],
conv['frac_digits'], x), grouping=True)
'$1,234,567.80'
模板
string
模块的类 Template
可渲染模板,通过占位符 $
指定位置填充实际数据,$$
将转为 $
from string import Template
# 1.定义模板
t = Template('${village}folk send $$10 to $cause.')
# 2.替换值,入参传字典也可以
t.substitute(village='Nottingham', cause='the ditch fund')
'Nottinghamfolk send $10 to the ditch fund.'
# 替换外来值
t.safe_substitute(d)
二进制
struct
模块提供了 pack
() 和 unpack
() 函数,用于处理不定长度的二进制记录格式
多线程
可使用 threading
, 提供多个同步操作原语,包括线程锁、事件、条件变量和信号量,但是仍可能导致一些难以复现的问题。因此,实现多任务协作的首选方法是将所有对资源的请求集中到一个线程中,然后使用 queue
模块向该线程供应来自其他线程的请求。 应用程序使用 Queue
对象进行线程间通信和协调,更易于设计,更易读,更可靠
日志
日志系统可以直接通过 Python 配置,也可以通过用户配置文件加载
import logging
logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning:config file %s not found', 'server.conf')
logging.error('Error occurred')
logging.critical('Critical error -- shutting down')
弱引用
weakref
模块提供的工具可以不必创建引用就能跟踪对象
import weakref, gc
class A:
def __init__(self, value):
self.value = value
def __repr__(self):
return str(self.value)
a = A(10) # create a reference
d = weakref.WeakValueDictionary()
d['primary'] = a # does not create a reference
>>> d['primary'] # fetch the object if it is still alive
10
>>> del a # remove the one reference
>>> gc.collect() # run garbage collection right away
0
>>> d['primary'] # entry was automatically removed
KeyError: 'primary'
Decimal
适合金融相关的计算场景,采用十进制浮点数,Python 基础类型float
采用二进制浮点数
from decimal import *
Decimal('1.00') % Decimal('.10')
Decimal('0.00')
1.00 % 0.10
0.09999999999999995
Unicodedata
一个完整的数据库(许多结构化文本文件),不仅包括码点与字符名称之间的映射表,还包括各个字符的元数据,以及字符之间的关系
💻 返回字符的名称 name()
没有则 ValueError
import unicodedata
>>> unicodedata.name('😂')
'FACE WITH TEARS OF JOY'
# 可传一个unicode字符码
>>> unicodedata.name('\u00e9')
'LATIN SMALL LETTER E WITH ACUTE'
💻返回名称对应的字符 lookip()
接受不区分大小写的标准名称,返回一个unicode字符
>>> unicodedata.lookup('LATIN CAPITAL LETTER A')
"A"
>>> unicodedata.lookup('LATIN SMALL LETTER E WITH ACUTE')
'é'
len()
计算字符串中unicode
字符的个数,而不是字节数
>>> len('\U0001f47b')
1
chr()
与 ord()
对 unicode 字符同样起作用
>>> chr(233)
'é'
>>> chr(0xe9)
'é'
>>> chr(0x1fc6)
'ῆ'
字符集统一化
>>> eacute1 = 'é' # UTF-8,直接粘贴
>>> eacute2 = '\u00e9' # Unicode代码点
>>> eacute3 = '\N{LATIN SMALL LETTER E WITH ACUTE}' # Unicode名称
>>> eacute4 = chr(233) # 十进制字节值
>>> eacute5 = chr(0xe9) # 十六进制字节值
>>> eacute1, eacute2, eacute3, eacute4, eacute5
('é', 'é', 'é', 'é', 'é')
>>> eacute1 == eacute2 == eacute3 == eacute4 == eacute5
True
如果 eacute
拼接其他字符集,尽管显示不变,但底层不再一样,可以用 unicodedata.normalize()
进行统一
eacute_normalized = unicodedata.normalize('NFC', "e\u0301")
Unicode 排序
第三方库 pyuca
>>> import pyuca
>>> coll = pyuca.Collator()
>>> fruits = ['caju', 'atemoia', 'cajá', 'açaí', 'acerola']
>>> sorted_fruits = sorted(fruits, key=coll.sort_key)
>>> sorted_fruits
['açaí', 'acerola', 'atemoia', 'cajá', 'caju']
html
🆕 Python 3.4 引入了一种方便转换 Unicode 字符的方法
import html
>>> html.unescape("è") # 'è'
# 有专门的 mapping
from html.entities import html5
>>> html5["egrave"] # 'è'
根据序号转为名称
char = '\u00e9'
dec_value = ord(char)
>>> html.entities.codepoint2name[dec_value]
'eacute'
struct
通过 struct
,可以在二进制数据和 Python 数据结构之间任意转换
import struct
valid_png_header = b'\x89PNG\r\n\x1a\n'
data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR' + \
... b'\x00\x00\x00\x9a\x00\x00\x00\x8d\x08\x02\x00\x00\x00\xc0'
# unpack() 将字节序列组合成 Python 数据类型
>>> if data[:8] == valid_png_header:
... width, height = struct.unpack('>LL', data[16:24])
... print('Valid PNG, width', width, 'height', height)
... else:
... print('Not a valid PNG')
...
Valid PNG, width 154 height 141
# Python 数据转成字节,用 pack()
>>> struct.pack('>L', 154)
b'\x00\x00\x00\x9a'
>
表示整数采用大端(big-endian)格式存储,小端用<
- 每个
L
指定一个长度为 4 字节的无符号长整数,可以写LL
,也可写2L
其他格式说明符:
说明符 | 描述 | 字节数 |
---|---|---|
x | 跳过一字节 | 1 |
b | 符号字节 | 1 |
B | 无符号字节 | 1 |
h | 有符号短整数 | 2 |
H | 无符号短整数 | 2 |
i | 有符号整数 | 4 |
I | 无符号整数 | 4 |
l | 有符号长整数 | 4 |
L | 无符号长整数 | 4 |
Q | 无符号长长(long long)整数 | 8 |
f | 单精度浮点数 | 4 |
d | 双精度浮点数 | 8 |
p | 数量和字符 | 1+ 数量 |
s | 字符 | 数量 |
🧲示例:>16x2L6x
表示,大端跳过 16 字节,读取 8 字节内容,跳过最后 6 字节
binascii
该标准库提供二进制数据和各种字符串描述(十六进制、base 64、uuencode 等)之间转换的函数
>>> import binascii
>>> valid_png_header = b'\x89PNG\r\n\x1a\n'
# 以 16 进制值序列的形式转换
>>> binascii.hexlify(valid_png_header)
b'89504e470d0a1a0a'
# 反向转换
>>> binascii.unhexlify(b'89504e470d0a1a0a')
b'\x89PNG\r\n\x1a\n'
re
使用需要定义一个模式 pattern
和一个源 source
,pattern
可以是普通字符,也可以是正则表达式
-
re.match()
⚠️ 只检查源是否以 pattern 开头!!
import re result = re.match('To', 'Today') # match() >>> result.pos 0 >>> result.span() (0, 2) re.findall(pat, source) # 查找全部 re.split('n', source) # 按照 pattern 切分字符串,返回列表 re.sub('a', 'b', source) # 将所有 a 替换成 b
-
re.complie()
将 pattern 预编译, 提高匹配速度
to_pattern = re.compile('To') result2 = to_pattern.match('Too busy right now') >>> result2.group() # 查看匹配内容 'To'
-
re.search()
在任意位置查找 pattern,找到返回一个
Match
对象,找不到则返回None
,只找第一个,区分大小写res = re.search('to', 'Too busy, too easy') >>> res <re.Match object; span=(10, 12), match='to'>
-
re.findall()
找到所有,返回列表
res = re.findall('to', 'too busy, too easy') >>> res ['to', 'to']
-
re.split()
分割res = re.split('to', 'too busy, too easy') >>> res ['', 'o busy, ', 'o easy']
-
re.sub()
替换res = re.sub('to', "TO",'too busy, too easy') >>> res 'TOo busy, TOo easy'
string
内置了 100 个可打印的 ASCII 字符
可用于测试正则表达式import string
>>> printable = string.printable
>>> printable
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
可用于测试正则表达式
可用于测试正则表达式# 找出所有数字
>>> re.findall('\d', printable)
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# 找出所有空白字符
>>> re.findall('\s', printable)
[' ', '\t', '\n', '\r', '\x0b', '\x0c']
END