前言
本人有一定的Python
基础,故记录的是自己不常用的或者是不太熟练的函数、模块
global和nonlocal关键字
- 局部变量:是在函数或代码块内部定义的变量,只在该函数或块的作用域内可见
- 全局变量:是在函数外部定义的变量,它在整个程序中都是可见的(但在函数中不能直接修改,除非使用
global
关键字)
注意:如果在函数中给一个变量赋值,那么这个变量会被默认认为是局部变量,即使函数外也有同名的局部变量
1 2 3 4 5 6 7 8
| x = 5
def my_function(): x = 10 print(x)
my_function() print(x)
|
重点:如果希望在函数内部修改全局变量的值,必须显式使用global
关键字
1 2 3 4 5 6 7 8 9
| x = 5
def my_function(): global x x = 10 print(x)
my_function() print(x)
|
注意:nonlocal
用于修改嵌套函数closure
中的外层局部变量(不是全局变量)
1 2 3 4 5 6 7 8 9
| def outer(): x = 5 def inner(): nonlocal x x = 10 inner() print(x)
outer()
|
如果没有nonlocal
,x = 10
会被视为inner()
的局部变量,外层变量不会被修改
类与初始化
一个类定义了一种数据结构,包括它的属性(变量)和方法(函数)。使用类,你可以创建多个具有相同结构的对象
1 2 3 4 5 6 7
| class 类名: def __init__(self, 参数1, 参数2): self.属性1 = 参数1 self.属性2 = 参数2 def 方法(self): pass
|
__init__()
方法详解
__init__()
是一个构造函数,在类创建对象时被自动调用
self
是对象自身的引用(表示当前对象本身),用于访问对象的属性和方法
1 2 3 4 5 6 7 8 9 10 11
| class Person: def __init__(self, name, age): self.name = name self.age = age
def say_hello(self): print(f"你好,我是 {self.name},我 {self.age} 岁了。")
p1 = Person("张三", 30) p1.say_hello()
|
后续可深入理解类的继承、多态、私有属性、类变量等内容
zip、lambda、map
zip():
并行打包多个可迭代对象
- 功能:将多个可迭代对象"打包"成一个 元组 的迭代器,适用于"配对"处理多个序列的情况
- 基本语法:
zip(iterable1, iterable2, ...)
- 注意:
zip()
会在最短的序列长度处"截断"
1 2 3 4 5
| names = ["张三", "李四", "王五"] scores = [90, 85, 92]
for name, score in zip(names, scores): print(f"{name} 的分数是 {score}")
|
lambda:
匿名函数
- 功能:快速创建小函数,常用于不需要复用的地方
- 基本语法:
lambda 参数1, 参数2: 表达式
1 2 3 4
| students = [("张三", 90), ("李四", 85), ("王五", 92)]
students_sorted = sorted(students, key=lambda x: x[1]) print(students_sorted)
|
map():
对序列进行映射操作
- 功能:对一个可迭代对象中每个元素执行相同的函数操作,返回一个
map
对象(可迭代)
- 基于语法:
map(function, iterable)
1 2 3
| nums = [1, 2, 3, 4] squares = list(map(lambda x: x**2, nums)) print(squares)
|
组合使用案例:
1 2 3 4 5
| a = [1, 2, 3] b = [10, 20, 30]
result = list(map(lambda x: x[0] * x[1], zip(a, b))) print(result)
|
浅拷贝和深拷贝
浅拷贝
- 创建一个新的对象,但不复制嵌套结构的子对象
- 原始对象中的子对象仍然是共享引用
深拷贝
- 创建一个新的对象,并递归地复制所有嵌套的子对象
- 原始对象与新对象完全独立
Python
使用copy
模块来处理浅拷贝和深拷贝:
1 2 3 4 5 6 7 8 9 10
| import copy
a = [1, 2, [3, 4]] b = copy.copy(a)
b[0] = 100 b[2][0] = 999
print("a:", a) print("b:", b)
|
1 2 3 4 5 6 7 8 9 10
| import copy
a = [1, 2, [3, 4]] b = copy.deepcopy(a)
b[0] = 100 b[2][0] = 999
print("a:", a) print("b:", b)
|
注意:赋值(=
)、浅拷贝copy()
、深拷贝deepcopy()
的区别
类型 |
是否创建新对象 |
是否复制子对象 |
是否共享引用 |
= 赋值 |
否 |
否 |
是(完全共享) |
copy.copy() |
是 |
否 |
是(嵌套共享) |
copy.deepcopy() |
是 |
是 |
否(完全独立) |
深拷贝对复杂结构或循环引用的数据结构可能比较慢且占内存
threading模块
threading
是Python
的标准库之一,用于实现多线程编程(即并发)。虽然Python
由于GIL(全局解释器锁)
的存在,在多线程CPU
密集型任务中有局限,但对于I/O
密集型任务(如文件读写、网络请求、数据库访问)来说,threading
是非常有效的
- 线程是程序执行的最小单位,是进程内的一个执行流。使用多线程可以同时处理多个任务,提高程序响应能力(尤其是等待
IO
的时候)
线程常用API
方法/属性 |
作用说明 |
Thread(target) |
创建线程 |
start() |
启动线程 |
join() |
等待线程结束 |
current_thread() |
获取当前线程对象 |
name |
线程名称 |
is_alive() |
判断线程是否还在运行 |
- 线程同步:线程之间共享数据时可能出现数据竞争问题,这时需要使用锁(
Lock
)来保护临界区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import threading
count = 0 lock = threading.Lock()
def worker(): global count for _ in range(100000): with lock: count += 1
threads = [threading.Thread(target=worker) for _ in range(2)] [t.start() for t in threads] [t.join() for t in threads]
print(count)
|
注意事项
Python
的GIL
会让多线程无法真正并行执行CPU
密集型任务
- 多线程适合处理
IO
密集型的任务(等待时间长,计算开销小)
- 对共享资源操作一定要用锁!
multiprocessing模块
Python
的multiprocessing
模块用于多进程并行处理任务,是处理CPU
密集型任务(如大规模计算、图像处理、模拟仿真)时的首选工具。它通过创建子进程来绕开Python
的GIL
,实现真正多核并行计算
进程池:Pool(批量任务处理)
:适合大量任务首发,自动管理进程数
1 2 3 4 5 6 7 8 9 10 11
| from multiprocessing import Pool import time
def square(n): time.sleep(1) return n * n
if __name__ == '__main__': with Pool(processes=4) as pool: results = pool.map(square, [1, 2, 3, 4, 5, 6]) print(results)
|
特点:
map()
会阻塞直到所有结果完成
apply_async()
为非阻塞版本
进程间通信(IPC
):多进程之间的数据不共享,需通过专用通道通信
使用Queue
1 2 3 4 5 6 7 8 9 10 11
| from multiprocessing import Process, Queue
def worker(q): q.put("你好,主进程!")
if __name__ == '__main__': q = Queue() p = Process(target=worker, args=(q,)) p.start() print(q.get()) p.join()
|
使用Pipe
1 2 3 4 5 6 7 8 9 10 11 12
| from multiprocessing import Process, Pipe
def sender(conn): conn.send("来自子进程的消息") conn.close()
if __name__ == '__main__': parent_conn, child_conn = Pipe() p = Process(target=sender, args=(child_conn,)) p.start() print(parent_conn.recv()) p.join()
|
共享数据:value
和Array
用于进程间共享简单变量或数组
1 2 3 4 5 6 7 8 9 10 11
| from multiprocessing import Process, Value
def add(val): val.value += 10
if __name__ == '__main__': num = Value('i', 100) p = Process(target=add, args=(num,)) p.start() p.join() print(num.value)
|
进程锁:避免多个进程同时修改共享数据
1 2 3 4 5 6 7 8 9 10
| from multiprocessing import Process, Lock
def task(lock, i): with lock: print(f"进程 {i} 正在写入")
if __name__ == '__main__': lock = Lock() for i in range(3): Process(target=task, args=(lock, i)).start()
|
pickle模块
pickle
模块是Python
标准库中用于序列化的工具,主要用于将Python
对象转换为字节流,以便存储到文件或通过网络传输,也可以从字节流还原成原始对象
- 序列化:将
Python
对象转换为字节流(或字符串)
- 反序列化:将字节流恢复为原来的
Python
对象
方法 |
说明 |
pickle.dump(obj, f) |
将对象序列化写入文件 |
pickle.load(f) |
从文件读取序列化内容并还原为对象 |
pickle.dumps(obj) |
将对象序列化为字节串 |
pickle.loads(bytes) |
从字节串反序列化为Python 对象 |
注意:pickle.load()
可以执行任意代码,有安全风险,容易被注入恶意代码
正则表达式
方法 |
说明 |
re.match(pattern, s) |
从字符串开头匹配pattern |
re.search(pattern, s) |
搜索整个字符串,返回第一个匹配 |
re.findall(pattern, s) |
返回所有匹配结果列表 |
re.finditer(pattern, s) |
返回所有匹配的迭代器对象 |
re.sub(pattern, repl, s) |
替换匹配到的内容为 repl |
re.compile(pattern) |
编译正则表达式,提高效率 |
1. 字符匹配
正则 |
含义 |
. |
任意一个字符(不包括换行符) |
\d |
一个数字(0-9) |
\D |
非数字字符 |
\w |
一个字母/数字/下划线 |
\W |
非字母/数字/下划线 |
\s |
空白字符(空格、换行、Tab) |
\S |
非空白字符 |
2. 量词(重复)
正则 |
含义 |
* |
匹配0次或多次 |
+ |
匹配1次或多次 |
? |
匹配0次或1次 |
{n} |
正好n次 |
{n,} |
至少n次 |
{n,m} |
n 到 m 次之间 |
3. 边界匹配
正则 |
含义 |
^ |
匹配字符串开头 |
$ |
匹配字符串结尾 |
\b |
单词边界 |
\B |
非单词边界 |
4. 分组与或
正则 |
含义 |
(abc) |
分组匹配 abc |
` |
` |
(?:abc) |
非捕获分组 |
- 多次使用同一正则时建议
compile
编译为模式对象,提高匹配速度
- 字符串前加
r""
防止\
被解释