目录
- 1 正则匹配
- 注意点1
- 1.1 正则匹配字符串写法
- 1.2 创建re函数
- (1)re.search()--搜索第一个匹配项
- (2)re.match() - 从字符串开头匹配
- (3)re.findall() - 返回所有匹配项的列表
- (4)re.finditer() - 返回匹配项的迭代器(适合大文本)
- (5)re.sub() - 替换匹配内容
- (6)re.split() - 按正则表达式分割字符串
- 2 参数数量/类型/默认值指定
- 3 引用传递和值传递说明
- 4 排列组合 itertools
- 5 内置变量/特殊变量
- 5.1 内置变量
- 5.2 类相关的特殊属性
- 6 try-except-else-finally机制
- 6.1 基础用法
- 6.2 else-finally
- 6.3 向上一级抛出错误
- 7 Threading - 线程(不是进程,创建进程我用的少)
- 7.1 讲到线程,就不得不谈线程通信
- 8 路径操作及路径索引 glob
以下资料参考官网及AI
1 正则匹配
re官网
python 的 re 库能够实现正则匹配功能。
注意点1
注意:在Python中使用正则表达式时要优先使用原始字符串。
(也就是说,字符串不会被python语言解析。而只会被re库里的函数解析)
原因如下:
正则表达式本身用 \ 转义特殊字符(如 \d 表示数字),但Python字符串中的 \ 也是转义符。因此,在普通字符串中写正则表达式时,需用 两个反斜杠 表示一个实际的反斜杠(如 \d)。
原始字符串(前缀 r)会忽略Python字符串的转义规则,直接保留所有字符的字面值。例如,r"\d" 会直接传递给正则引擎 \d,而无需额外转义。
以下为错误案例1:
python">import repattern = "\\" # 普通字符串:实际传递的是单个 \,但正则引擎会报错(转义不完整)
re.findall(pattern, "a\\b") # 报错:因为正则收到的是单个 \
正确写法:
python">pattern = "\\\\" # 普通字符串中,四个反斜杠 → Python转义为两个 \,正则引擎收到两个 \
result = re.findall(pattern, "a\\b") # 成功匹配到 ["\\"]
使用原始字符串的写法:
python">pattern = r"\\" # 原始字符串直接保留两个 \,正则引擎收到两个 \
result = re.findall(pattern, "a\\b") # 成功匹配到 ["\\"]
以下为错误案例2:
python">pattern = "\b" # 普通字符串中,\b 是退格符,正则引擎无法识别为单词边界
re.findall(pattern, "hello world") # 匹配失败
正确写法:
python">pattern = r"\b" # 原始字符串直接传递 \b,正则引擎识别为单词边界
result = re.findall(pattern, "hello world") # 匹配到单词边界的空字符
1.1 正则匹配字符串写法
pattern = r'xxx'
匹配字符 | 含义 | 案例 |
---|---|---|
[ ] | 一个字符的集合,这写字符可以单独列出,也可以用范围表示(范围用- 分隔) | [abc],[a-c] |
$ | [akm$] 将会匹配以下任一字符 ‘a’, ‘k’, ‘m’ 或 ‘$’ | |
^ | 把 ^ 放在字符类的最开头,集合取反来匹配字符类中未列出的字符。(如果放在字符类其他位置,则无意义) | [^5] 将匹配除 ‘5’ 之外的任何字符;[5^] 将匹配 ‘5’ 或 ‘^’ |
\w | 匹配任何字母数字字符 | 相当于字符类 [a-zA-Z0-9_] |
\d | 匹配任何十进制数字 | 等价于字符类 [0-9] |
\S | 匹配任何非空白字符 | 等价于字符类 [^ \t\n\r\f\v] |
\W | 匹配任何非字母与数字字符 | 等价于字符类 [^a-zA-Z0-9_] |
\s | 匹配任何空白字符 | [ \t\n\r\f\v] |
\D | 匹配任何非数字字符 | 等价于字符类 [^0-9] |
. | 匹配除换行符之外的任何字符 | |
* | 定前一个字符可以匹配零次或更多次,而不是只匹配一次 | ca*t 将匹配 ‘ct’ ( 0 个 ‘a’ )、‘cat’ ( 1 个 ‘a’ )、 ‘caaat’ ( 3 个 ‘a’ ) |
+ | 匹配一次或更多次 | ca+t 可以匹配 ‘cat’ ( 1 个 ‘a’ )或 ‘caaat’ ( 3 个 ‘a’),但不能匹配 ‘ct’ |
{m,n} | 其中 m 和 n 是十进制整数,该限定符意味着必须至少重复 m 次,最多重复 n 次。 | a/{1,3}b 可以匹配 ‘a/b’、‘a//b’ 或者 ‘a///b’ ,但不能匹配中间没有斜杆的 ‘ab’,或者四个斜杆的 ‘ab’ |
() | 它们将包含在其中的表达式组合在一起,你可以使用重复限定符重复组的内容 | (ab)*,匹配ab 0到多次 |
1.2 创建re函数
(1)re.search()–搜索第一个匹配项
python">import retext = "Python is fun, Python is powerful"
pattern = r"Python"
match = re.search(pattern, text)
if match:print("Found:", match.group()) # 输出: Found: Python
(2)re.match() - 从字符串开头匹配
python">import re
text = "Python is awesome"
pattern = r"Python"
match = re.match(pattern, text)
if match:print("Match found:", match.group()) # 输出: Match found: Python# 若 text = "I love Python",则 match 为 None
(3)re.findall() - 返回所有匹配项的列表
python">import re
text = "apple 12, banana 3, cherry 45"
numbers = re.findall(r'\d+', text)
print(numbers) # 输出: ['12', '3', '45']
(4)re.finditer() - 返回匹配项的迭代器(适合大文本)
python">import re
text = "a=1, b=2, c=3"
matches = re.finditer(r'\w+=\d+', text)
for match in matches:print(match.group()) # 输出: a=1, b=2, c=3
(5)re.sub() - 替换匹配内容
python">import re
text = "2023-10-05"
new_text = re.sub(r'-', '/', text)
print(new_text) # 输出: 2023/10/05# 使用函数处理替换内容
def double_number(match):return str(int(match.group()) * 2)text = "Score: 5, Count: 3"
result = re.sub(r'\d+', double_number, text)
print(result) # 输出: Score: 10, Count: 6
(6)re.split() - 按正则表达式分割字符串
python">import re
text = "one,two;three four"
parts = re.split(r'[,; ]+', text)
print(parts) # 输出: ['one', 'two', 'three', 'four']
2 参数数量/类型/默认值指定
直接通过一个综合案例说明:
python">from typing import Union, Optional, Anydef generate_user_card(username: str, # 必选参数(无默认值)age: int = 18, # 必选但有默认值(可省略)*hobbies: str, # 不定数量的位置参数(爱好)country: Optional[str] = "未知", # 可选关键字参数(允许None)**extra_info: Union[str, int, float] # 不定数量的关键字参数(扩展信息)
) -> dict[str, Any]:"""生成用户信息卡,支持灵活参数输入"""user_data = {"username": username,"age": age,"hobbies": hobbies if hobbies else ("无",),"country": country,"extra": extra_info}return user_data
(1)基础调用:
python">
result1 = generate_user_card("Alice")
print(result1)
# {'username': 'Alice', 'age': 18, 'hobbies': ('无',), 'country': '未知', 'extra': {}}
(2)额外信息传入:
python">result3 = generate_user_card("Charlie",age=30,country=None, # 明确设置为Noneemail="charlie@example.com",score=95.5
)
print(result3["extra"])
# {'email': 'charlie@example.com', 'score': 95.5}
3 引用传递和值传递说明
在 Python 中,变量传递的本质是 对象引用的传递,所有操作都是基于对象的引用(可以理解为“指针”)。
-
不可变对象(int, float, str, tuple 等)
传递的是对象的引用,但修改时会创建新对象,原始对象不受影响(类似“值传递”的效果)。 -
可变对象(list, dict, set, 自定义类实例等)
传递的是对象的引用,修改内容时会影响原始对象(类似“引用传递”的效果)。
案例说明1
python">def modify_data(num: int, lst: list, obj: object):num += 10 # 不可变对象:创建新对象lst.append(4) # 可变对象:修改原对象obj.value = 5 # 可变对象:修改原对象# 初始化数据
original_num = 5
original_list = [1, 2, 3]
class MyClass:def __init__(self):self.value = 0
original_obj = MyClass()# 调用函数
modify_data(original_num, original_list, original_obj)print(original_num) # 输出 5(未改变)
print(original_list) # 输出 [1, 2, 3, 4](已改变)
print(original_obj.value) # 输出 5(已改变)
案例2
python">class DataHolder:def __init__(self, data):self.data = data # data 是可变/不可变对象的引用# 不可变对象操作
holder1 = DataHolder(10)
temp = holder1.data
temp += 5 # 创建新对象,不影响原数据
print(holder1.data) # 输出 10# 可变对象操作
holder2 = DataHolder([1, 2])
holder2.data.append(3) # 直接修改原对象
print(holder2.data) # 输出 [1, 2, 3]
案例3:修改和赋值的本质区别
python">a = [1, 2]
b = a # 引用传递(指向同一对象)
b.append(3) # 修改原对象
print(a) # 输出 [1, 2, 3]c = [4, 5]
d = c
d = [6, 7] # 创建新对象(重新绑定引用)
d.append(10)
print(c) # 输出 [4, 5](原对象未变)
注意,这里:
lst = lst + (创建新列表,不影响原对象)
lst.append(4)(原地修改,影响原对象)
案例4:默认参数陷阱
python"># 错误示例:默认参数为可变对象
def buggy_func(data=[]): # 默认列表会持续保留data.append(1)return data# 正确做法
def safe_func(data=None):data = data if data is not None else []data.append(1)return data
错误案例的进一步测试:
python">def func(data=[]):data.append(1)return datafunc()
data = func()
data.append(10)
func()
print(data) # 输出:[1, 1, 10, 1]
4 排列组合 itertools
tee 生成迭代器副本(副本的修改不影响原始数据)
islice 切片
zip_longest 合并多个迭代器
python">import itertoolsl = [1,2,3,4]
iter1, iter2 = itertools.tee(l, 2)
for x in iter1:
#
itertools.zip_longest()
5 内置变量/特殊变量
5.1 内置变量
python所有的内置变量:
python">dir(__builtins__)
__name__
如果当前运行的python文件为主文件,则该文件:
__name__ == __main__
如果当前文件被其他文件调用,则该文件:
__name__ == [文件名]
(不带.py后缀)
参考文章
5.2 类相关的特殊属性
__slots__
限制class可绑定的类的属性。
python">__slots__ = ['属性名1','属性名2','属性名3']
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
__init__
类默认构造函数 ,第一个参入参数为self
__lt__
@property装饰器
将方法变成属性调用。
__str__
6 try-except-else-finally机制
6.1 基础用法
python">try:with open('example.txt', 'r') as file:content = file.read()print(content)
except FileNotFoundError:print("文件未找到,请检查文件路径是否正确。")
except PermissionError:print("没有权限读取该文件。")
except Exception as e:# 捕获所有其他类型的异常print(f"发生了一个错误:{e}")
try: 放置可能引发异常的代码。‘
except:如果try中的代码引发异常,会跳转到指定的except 块儿中
as: as e是可选的,允许你将异常实例赋值给变量e,这样就可以在except块中访问到异常信息。
Exception :代表不指定异常类型(反之捕获所有异常)
Python会按照except块的顺序检查,一旦找到匹配的异常类型,就会执行该块中的代码,并且跳过后续的except块。
6.2 else-finally
python">try:# 尝试执行的代码pass
except SomeException:# 处理异常的代码pass
else:# 如果没有异常发生,执行这里的代码pass
finally:# 无论是否发生异常,都执行这里的代码pass
else:如果你想要在没有异常发生时执行一些代码,可以使用else块。它紧跟在所有的except块之后,只有在try块没有引发任何异常时才会执行。
finally:无论是否发生异常,finally块中的代码都会被执行。这通常用于执行一些清理工作,比如关闭文件或释放资源。
6.3 向上一级抛出错误
raise [error]
注意:如果不抛出错误,程序在执行换except后就会退出吗?
当except块内部的操作执行完成后,程序并不会自动退出,除非你在except块中显式地调用了sys.exit()、exit()、os._exit()等函数来终止程序,或者异常没有被捕获并且传播到了程序的顶层(即没有被任何try块捕获)。
7 Threading - 线程(不是进程,创建进程我用的少)
感谢大佬的总结:
https://liaoxuefeng.com/books/python/process-thread/thread/index.html
说实话,之前只用过C thread,没用过python。
这里对大佬的 文章列出一些关键点:
(1)启动一个线程就是把一个函数传入并创建Thread实例,然后==调用start()==开始执行。
(2)在Python中,可以使用多线程,但不要指望能有效利用多核
python">
有一些久远的记忆似乎在逐渐复苏
7.1 讲到线程,就不得不谈线程通信
线程的特点就是,共享资源,任务间需要频繁通信。
线程的关键点就是:通信和同步。
要避免的问题:死锁
(1)互斥锁
(2)信号量
(3)条件变量
(4)事件
(5)消息队列
(6)管道
8 路径操作及路径索引 glob
主要利用glob2库
python">from glob2 import globpaths = glob(file_path) # 搜索文件file_path下所有文件,返回list变量# 返回该路径下所有文件