Python字符串從入門到精通的實(shí)戰(zhàn)指南
1. 字符串創(chuàng)建與基本操作
1.1 四種創(chuàng)建方式
Python 提供了四種引號方式來創(chuàng)建字符串,它們在語法上等價(jià),但各有適用場景:
# ========== 四種創(chuàng)建方式 ========== s1 = '單引號字符串' # 最常用,適合短文本 s2 = "雙引號字符串" # 與單引號等價(jià),適合包含單引號的內(nèi)容 s3 = '''三重單引號 可以換行 多行文本''' # 多行字符串 s4 = """三重雙引號 也可以換行 多行文本""" # 多行字符串,常作文檔字符串(docstring) print(type(s1)) # <class 'str'> print(s1) # 單引號字符串 print(s3) # 三重單引號\n可以換行\(zhòng)n多行文本(實(shí)際輸出會(huì)換行)
單引號 vs 雙引號的選擇原則:
# 原則:外層引號與內(nèi)層引號不同,避免轉(zhuǎn)義 msg1 = "It's a beautiful day" # ? 外雙內(nèi)單,無需轉(zhuǎn)義 msg2 = 'He said "Hello"' # ? 外單內(nèi)雙,無需轉(zhuǎn)義 msg3 = 'It\'s a beautiful day' # ?? 可以但沒必要,轉(zhuǎn)義降低可讀性 # 團(tuán)隊(duì)規(guī)范:選擇一種風(fēng)格保持統(tǒng)一,推薦雙引號(PEP 257 docstring 用三雙引號)
1.2 原始字符串與轉(zhuǎn)義
# ========== 轉(zhuǎn)義字符速查 ==========
print("換行符: \n") # 換行
print("制表符: \t") # 制表
print("反斜杠: \\") # 反斜杠本身
print("單引號: \'") # 單引號
print("雙引號: \"") # 雙引號
print("回車符: \r") # 回車(覆蓋行首)
# ========== 原始字符串 r"" ==========
# Windows 路徑 —— 不用 r 就得雙重轉(zhuǎn)義
path1 = "C:\\Users\\yance\\Desktop" # 普通字符串,每個(gè) \ 都要轉(zhuǎn)義
path2 = r"C:\Users\yance\Desktop" # 原始字符串,所見即所得 ?
# 正則表達(dá)式 —— 不用 r 就變成"轉(zhuǎn)義地獄"
import re
# 匹配數(shù)字 \d,不用 r 的話:
re.compile("\\d+") # Python 先轉(zhuǎn)義為 \d,re 再解釋為數(shù)字
# 用 r 的話:
re.compile(r"\d+") # 直達(dá)正則引擎,清晰明了 ?
# ?? 原始字符串的陷阱:不能以奇數(shù)個(gè)反斜杠結(jié)尾
# r"hello\" # SyntaxError! 反斜杠轉(zhuǎn)義了結(jié)尾引號
r"hello\\" # ? 等價(jià)于 "hello\\"
1.3 f-string 格式化(Python 3.6+)
Python 歷史上出現(xiàn)了三種字符串格式化方式,f-string 是目前的最優(yōu)解:
name = "yance"
age = 28
score = 95.678
# ========== 三種格式化方式對比 ==========
# ? % 格式化(C 風(fēng)格,老舊不推薦)
print("Name: %s, Age: %d" % (name, age))
# ? str.format()(Python 2.6+,可讀性一般)
print("Name: {}, Age: {}".format(name, age))
print("Name: {0}, Age: {1}".format(name, age))
# ? f-string(Python 3.6+,推薦 ?)
print(f"Name: {name}, Age: {age}")
# ========== f-string 高級用法 ==========
# 表達(dá)式求值
print(f"Next year: {age + 1}") # 直接運(yùn)算
print(f"Name upper: {name.upper()}") # 調(diào)用方法
print(f"Len: {len(name)}") # 調(diào)用函數(shù)
# 格式控制:{value:format_spec}
print(f"Score: {score:.2f}") # 保留2位小數(shù) → 95.68
print(f"Score: {score:>10.2f}") # 右對齊,寬度10 → 95.68
print(f"Score: {score:<10.2f}") # 左對齊 → 95.68
print(f"Score: {score:^10.2f}") # 居中 → 95.68
print(f"Score: {score:0>10.2f}") # 前補(bǔ)零 → 0000095.68
# 數(shù)字格式化
num = 1234567
print(f"千分位: {num:,}") # 1,234,567
print(f"百分比: {0.856:.1%}") # 85.6%
print(f"科學(xué)計(jì)數(shù): {num:.2e}") # 1.23e+06
print(f"二進(jìn)制: {42:b}") # 101010
print(f"十六進(jìn)制: {255:x}") # ff
print(f"八進(jìn)制: {255:o}") # 377
# Python 3.8+ 調(diào)試語法 =(變量名=值)
x = 42
print(f"{x = }") # x = 42
print(f"{x * 2 = }") # x * 2 = 84
print(f"{name = !r}") # name = 'yance' (!r 顯示引號)
格式化方式對比總結(jié):
| 方式 | 版本 | 可讀性 | 性能 | 推薦度 |
|---|---|---|---|---|
%s | 全版本 | ★★☆ | ★★☆ | ?? 僅維護(hù)老代碼 |
.format() | 2.6+ | ★★★ | ★★★ | ?? 兼容舊版本時(shí)用 |
f-string | 3.6+ | ★★★★ | ★★★★ | ? 首選 |
1.4 字符串拼接與乘法
# ========== 拼接方式 ==========
# ? + 號拼接(少量字符串)
greeting = "Hello" + " " + "World" # "Hello World"
# ? join 拼接(大量字符串,性能最優(yōu))?
words = ["Python", "is", "awesome"]
sentence = " ".join(words) # "Python is awesome"
# ? f-string 拼接(現(xiàn)代寫法)?
lang = "Python"
sentence = f"{lang} is awesome"
# ?? 性能對比:+ 號 vs join
import time
def concat_plus(n=100000):
s = ""
for i in range(n):
s += "a"
return s
def concat_join(n=100000):
return "".join("a" for _ in range(n))
# join 比 + 快約 2-3 倍(CPython 對 += 有優(yōu)化,但 join 仍更優(yōu))
# ========== 字符串乘法 ==========
separator = "-" * 40 # "----------------------------------------"
indent = " " * 3 # 12個(gè)空格
pattern = "ab" * 5 # "ababababab"
print(separator)
2. 索引、切片與步進(jìn)
2.1 索引機(jī)制
Python 字符串支持雙向索引:正索引從 0 開始,負(fù)索引從 -1 開始。
字符串: P y t h o n 正索引: 0 1 2 3 4 5 負(fù)索引: -6 -5 -4 -3 -2 -1
s = "Python" # ========== 正索引 ========== print(s[0]) # 'P' 首字符 print(s[5]) # 'n' 末字符 # ========== 負(fù)索引 ========== print(s[-1]) # 'n' 末字符(最常用?。? print(s[-6]) # 'P' 首字符 print(s[-2]) # 'o' 倒數(shù)第二個(gè) # ========== 索引越界 ========== # s[6] # IndexError: string index out of range # s[-7] # IndexError: string index out of range
2.2 切片 [start:stop:step]
切片是 Python 最優(yōu)雅的特性之一,左閉右開,不會(huì)越界報(bào)錯(cuò):
s = "ABCDEFGHIJ" # 0123456789 # ========== 基礎(chǔ)切片 ========== print(s[2:5]) # 'CDE' 索引 2,3,4(不含5) print(s[:5]) # 'ABCDE' 從頭到索引4 print(s[5:]) # 'FGHIJ' 從索引5到末尾 print(s[:]) # 'ABCDEFGHIJ' 完整拷貝 # ========== 負(fù)索引切片 ========== print(s[-3:]) # 'HIJ' 最后3個(gè)字符 print(s[:-3]) # 'ABCDEFG' 除最后3個(gè)之外 print(s[-5:-2]) # 'FGH' 倒數(shù)第5到倒數(shù)第3(不含-2) # ========== 越界安全 ========== print(s[5:100]) # 'FGHIJ' 不報(bào)錯(cuò),取到末尾 print(s[100:200]) # '' 不報(bào)錯(cuò),返回空串
2.3 步進(jìn) step
步進(jìn)(step)控制切片的方向和跨度:
s = "ABCDEFGHIJ" # ========== 正向步進(jìn) ========== print(s[::2]) # 'ACEGI' 每隔1個(gè)取1個(gè)(奇數(shù)位) print(s[1::2]) # 'BDFHJ' 偶數(shù)位 print(s[::3]) # 'ADGJ' 每隔2個(gè)取1個(gè) # ========== 反向步進(jìn)(負(fù)步進(jìn)) ========== print(s[::-1]) # 'JIHGFEDCBA' 反轉(zhuǎn)字符串!最常用技巧 ? print(s[::-2]) # 'JHFDB' 反向每隔1個(gè)取1個(gè) print(s[8:2:-1]) # 'IHGFED' 從索引8反向切到索引3 print(s[7:2:-2]) # 'HFD' 反向每隔1個(gè) # ========== 步進(jìn)方向與起止方向必須一致 ========== print(s[2:8:-1]) # '' 步進(jìn)是反向,但起止是正向 → 空串 print(s[8:2:1]) # '' 步進(jìn)是正向,但起止是反向 → 空串
切片速記口訣:
切片左閉右開取,起止省略到兩頭。 步進(jìn)為正從左走,步進(jìn)為負(fù)往右搜。 方向沖突空串還,越界安全不報(bào)錯(cuò)。
2.4 切片賦值?—— 字符串不可變!
s = "Python"
# s[0] = "J" # TypeError: 'str' object does not support item assignment
# 修改字符串的唯一方式:創(chuàng)建新字符串
s = "J" + s[1:] # 'Jython' 拼接新串
s = s.replace("J", "P") # 'Python' 用方法返回新串
# 不可變的好處:
# 1. 可以安全地作為字典的 key
# 2. 多個(gè)變量可以共享同一字符串對象(內(nèi)存優(yōu)化)
# 3. 線程安全
3. 常用方法詳解
3.1 查找類:find / index / count / rfind
s = "Hello, Python! Python is great."
# ========== find / rfind ==========
# find(sub, start, end) → 返回子串首次出現(xiàn)的索引,找不到返回 -1
print(s.find("Python")) # 7 首次出現(xiàn)
print(s.find("Python", 10)) # 15 從索引10開始找
print(s.find("Java")) # -1 找不到
print(s.rfind("Python")) # 15 最后一次出現(xiàn)的索引
# ========== index / rindex ==========
# index 與 find 功能相同,但找不到時(shí)拋出 ValueError
print(s.index("Python")) # 7
# s.index("Java") # ValueError: substring not found
# ========== count ==========
print(s.count("Python")) # 2 出現(xiàn)次數(shù)
print(s.count("o")) # 2
print(s.count("z")) # 0
# ========== find vs index 選擇建議 ==========
# 確定子串存在時(shí)用 index(找不到是異常,暴露 bug)
# 不確定子串是否存在時(shí)用 find(找不到返回 -1,正常邏輯)
3.2 替換:replace
s = "Hello, World! World is beautiful."
# ========== 基本替換 ==========
print(s.replace("World", "Python"))
# "Hello, Python! Python is beautiful."
# 默認(rèn)替換所有出現(xiàn)
# ========== 限制替換次數(shù) ==========
print(s.replace("World", "Python", 1))
# "Hello, Python! World is beautiful." 只替換第1個(gè)
# ========== 鏈?zhǔn)教鎿Q ==========
result = s.replace("World", "Python").replace("beautiful", "awesome")
print(result)
# "Hello, Python! Python is awesome."
# ?? replace 返回新字符串,原字符串不變(字符串不可變?。?
original = "abc"
new = original.replace("b", "X") # "aXc"
print(original) # "abc" 原串未變
3.3 分割與合并:split / rsplit / splitlines / join
# ========== split / rsplit ==========
csv_data = "name,age,city"
print(csv_data.split(",")) # ['name', 'age', 'city']
# 限制分割次數(shù)
text = "a-b-c-d-e"
print(text.split("-", 2)) # ['a', 'b', 'c-d-e'] 從左分割2次
print(text.rsplit("-", 2)) # ['a-b-c', 'd', 'e'] 從右分割2次
# 默認(rèn)按空白字符分割(空格、Tab、換行都行)
messy = " hello world \t python \n "
print(messy.split()) # ['hello', 'world', 'python']
# ========== splitlines ==========
multiline = "第一行\(zhòng)n第二行\(zhòng)r\n第三行\(zhòng)r第四行"
print(multiline.splitlines()) # ['第一行', '第二行', '第三行', '第四行']
# 自動(dòng)識別 \n, \r\n, \r 三種換行符
# ========== join(split 的逆操作)==========
words = ["Python", "is", "awesome"]
print(" ".join(words)) # "Python is awesome"
print("-".join(words)) # "Python-is-awesome"
print("".join(words)) # "Pythonisawesome"
# 經(jīng)典用法:路徑拼接
import os
dirs = ["home", "yance", "projects"]
path = "/".join(dirs) # "home/yance/projects"
# 實(shí)際項(xiàng)目推薦 os.path.join() 或 pathlib
# ?? join 只能連接字符串列表,數(shù)字需要先轉(zhuǎn)換
nums = [1, 2, 3]
# ",".join(nums) # TypeError!
print(",".join(str(n) for n in nums)) # "1,2,3" ?
3.4 去除空白:strip / lstrip / rstrip
# ========== 基本去空白 ==========
s = " Hello, World! "
print(s.strip()) # "Hello, World!" 兩端去除
print(s.lstrip()) # "Hello, World! " 去除左端
print(s.rstrip()) # " Hello, World!" 去除右端
# ========== 去除指定字符 ==========
# strip(chars) —— 去除兩端所有在 chars 中的字符(不是去除子串?。?
s2 = "***Hello***"
print(s2.strip("*")) # "Hello"
s3 = "xxxPythonxxx"
print(s3.strip("x")) # "Python"
s4 = "ABChelloCBA"
print(s4.strip("ABC")) # "hello" A/B/C 都會(huì)被去除
# ?? 常見誤區(qū)
s5 = " Hello World "
print(s5.strip()) # "Hello World" 只去兩端,中間空格保留!
s6 = "abchelloabc"
print(s6.strip("abc")) # "hello" 不是去子串"abc",是去 a/b/c 三個(gè)字符
# ========== 實(shí)際應(yīng)用 ==========
# 讀取用戶輸入時(shí)幾乎總要 strip
user_input = input("請輸入: ").strip()
# 清洗 CSV 數(shù)據(jù)
raw_fields = [" Alice ", " 28 ", " Beijing "]
clean = [f.strip() for f in raw_fields] # ['Alice', '28', 'Beijing']
3.5 編碼與解碼:encode / decode
# ========== encode: str → bytes ==========
s = "你好,Python"
print(type(s)) # <class 'str'>
b_utf8 = s.encode("utf-8") # UTF-8 編碼(推薦 ?)
b_gbk = s.encode("gbk") # GBK 編碼(中文 Windows 常見)
print(b_utf8) # b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8cPython'
print(b_gbk) # b'\xc4\xe3\xba\xc3\xa3\xacPython'
# ========== decode: bytes → str ==========
print(b_utf8.decode("utf-8")) # "你好,Python"
print(b_gbk.decode("gbk")) # "你好,Python"
# ?? 編解碼必須一致,否則亂碼或報(bào)錯(cuò)
# b_utf8.decode("gbk") # UnicodeDecodeError 或亂碼!
# ========== 錯(cuò)誤處理策略 ==========
bad_bytes = b"\xff\xfe invalid"
print(bad_bytes.decode("utf-8", errors="ignore")) # " invalid" 忽略錯(cuò)誤字節(jié)
print(bad_bytes.decode("utf-8", errors="replace")) # "?? invalid" 替換為?
print(bad_bytes.decode("utf-8", errors="backslashreplace")) # "\\xff\\xfe invalid"
# ========== 常用場景 ==========
# 1. 網(wǎng)絡(luò)傳輸
data = "Hello".encode("utf-8") # 發(fā)送前編碼
msg = data.decode("utf-8") # 接收后解碼
# 2. 文件讀寫
with open("test.txt", "w", encoding="utf-8") as f: # 指定編碼
f.write("你好")
# 3. 判斷編碼
import chardet
raw = "你好".encode("gbk")
result = chardet.detect(raw) # {'encoding': 'GB2312', 'confidence': 0.99, ...}
3.6 其他常用方法速查
s = "Hello, Python!"
# ========== 大小寫 ==========
print(s.upper()) # "HELLO, PYTHON!" 全大寫
print(s.lower()) # "hello, python!" 全小寫
print(s.title()) # "Hello, Python!" 每個(gè)單詞首字母大寫
print(s.capitalize()) # "Hello, python!" 僅首字母大寫
print(s.swapcase()) # "hELLO, pYTHON!" 大小寫互換
# ========== 判斷類 ==========
print("123".isdigit()) # True 是否全是數(shù)字
print("abc".isalpha()) # True 是否全是字母
print("abc123".isalnum()) # True 是否全是字母或數(shù)字
print(" ".isspace()) # True 是否全是空白
print("Hello".isupper()) # False 是否全大寫
print("hello".islower()) # True 是否全小寫
print("Hello World".istitle()) # True 是否標(biāo)題格式
# ========== 填充對齊 ==========
print("Python".center(20, "-")) # "-------Python-------"
print("Python".ljust(20, "-")) # "Python--------------"
print("Python".rjust(20, "-")) # "--------------Python"
print("42".zfill(6)) # "000042" 左補(bǔ)零(處理編號常用)
# ========== 前綴后綴 ==========
print("test.py".startswith("test")) # True
print("test.py".endswith(".py")) # True
# 支持元組參數(shù)
print("test.py".endswith((".py", ".txt"))) # True
# ========== 判斷包含 ==========
print("Python" in "I love Python") # True 推薦方式 ?
print("Java" not in "I love Python") # True
4. 正則表達(dá)式入門:re 模塊核心 API
4.1 正則表達(dá)式是什么?
正則表達(dá)式(Regular Expression,簡稱 regex)是一種模式匹配語言,用于在文本中搜索、匹配、替換符合特定規(guī)則的字符串。
普通字符串查找: "error" in log → 只能找固定文本 正則表達(dá)式查找: re.search(r"error\d+", log) → 能找 error42、error007 等模式
4.2 核心元字符速查表
| 元字符 | 含義 | 示例 | 匹配 |
|---|---|---|---|
. | 任意單個(gè)字符(除換行) | a.c | abc, a1c, a c |
^ | 行首 | ^Hello | 行首的 Hello |
$ | 行尾 | world$ | 行尾的 world |
* | 前一項(xiàng) 0 次或多次 | ab*c | ac, abc, abbc |
+ | 前一項(xiàng) 1 次或多次 | ab+c | abc, abbc |
? | 前一項(xiàng) 0 次或 1 次 | ab?c | ac, abc |
{n} | 前一項(xiàng)恰好 n 次 | \d{3} | 123 |
{n,m} | 前一項(xiàng) n 到 m 次 | \d{2,4} | 12, 123, 1234 |
[] | 字符集 | [aeiou] | a, e, i, o, u |
[^] | 取反字符集 | [^0-9] | 非數(shù)字 |
() | 分組(捕獲) | (ab)+ | ab, abab |
| | 或 | cat|dog | cat 或 dog |
\d | 數(shù)字 [0-9] | \d+ | 42, 007 |
\w | 單詞字符 [a-zA-Z0-9_] | \w+ | hello_42 |
\s | 空白字符 | \s+ | 空格/Tab/換行 |
\D | 非數(shù)字 | \D+ | abc |
\W | 非單詞字符 | \W+ | !@# |
\S | 非空白 | \S+ | 非空白序列 |
4.3 re 模塊六大核心 API
import re
text = "My phone is 138-1234-5678 and office is 010-8765-4321"
# ========== ? re.search() —— 搜索第一個(gè)匹配 ==========
# 掃描整個(gè)字符串,返回第一個(gè)匹配的 Match 對象或 None
match = re.search(r"\d{3}-\d{4}-\d{4}", text)
if match:
print(f"找到: {match.group()}") # 138-1234-5678
print(f"位置: {match.start()}-{match.end()}") # 位置: 12-27
print(f"span: {match.span()}") # (12, 27)
# ========== ? re.match() —— 只匹配字符串開頭 ==========
# 僅在字符串開頭匹配,開頭不匹配則返回 None
result1 = re.match(r"My", text) # ? 匹配成功
result2 = re.match(r"phone", text) # None,不在開頭
# 實(shí)際開發(fā)中更推薦用 search + ^ 代替 match
result3 = re.search(r"^My", text) # 等價(jià)于 match
# ========== ? re.findall() —— 找出所有匹配,返回列表 ==========
phones = re.findall(r"\d{3}-\d{4}-\d{4}", text)
print(phones) # ['138-1234-5678', '010-8765-4321']
# 帶分組的 findall —— 返回分組內(nèi)容的元組列表
pattern = r"(\d{3})-(\d{4})-(\d{4})"
groups = re.findall(pattern, text)
print(groups) # [('138', '1234', '5678'), ('010', '8765', '4321')]
# ========== ? re.finditer() —— 迭代器版 findall ==========
# 返回迭代器,每個(gè)元素是 Match 對象(比 findall 更節(jié)省內(nèi)存)
for m in re.finditer(r"\d{3}-\d{4}-\d{4}", text):
print(f"Phone: {m.group()}, Position: {m.span()}")
# ========== ? re.sub() —— 替換 ==========
# re.sub(pattern, replacement, string, count=0)
# 隱藏手機(jī)號中間四位
hidden = re.sub(r"(\d{3})-\d{4}-(\d{4})", r"\1-****-\2", text)
print(hidden) # My phone is 138-****-5678 and office is 010-****-4321
# 使用函數(shù)作為 replacement
def mask_phone(match):
return f"{match.group(1)}-****-{match.group(3)}"
hidden2 = re.sub(r"(\d{3})-(\d{4})-(\d{4})", mask_phone, text)
# ========== ? re.split() —— 正則分割 ==========
# 按多種分隔符分割
data = "one,two;three|four"
result = re.split(r"[,;|]", data)
print(result) # ['one', 'two', 'three', 'four']
# 帶捕獲組的 split —— 分隔符也會(huì)出現(xiàn)在結(jié)果中
result2 = re.split(r"([,;|])", data)
print(result2) # ['one', ',', 'two', ';', 'three', '|', 'four']
4.4 Match 對象常用方法
import re
text = "Order #12345, total: $99.50"
match = re.search(r"Order #(\d+), total: \$(\d+\.\d+)", text)
if match:
match.group() # 'Order #12345, total: $99.50' 完整匹配
match.group(0) # 同上,0 = 整體匹配
match.group(1) # '12345' 第1個(gè)分組
match.group(2) # '99.50' 第2個(gè)分組
match.groups() # ('12345', '99.50') 所有分組元組
match.start() # 0 匹配起始位置
match.end() # 29 匹配結(jié)束位置
match.span() # (0, 29) 匹配范圍
# 命名分組(更可讀)
match2 = re.search(r"Order #(?P<id>\d+), total: \$(?P<amount>\d+\.\d+)", text)
match2.group("id") # '12345'
match2.group("amount") # '99.50'
match2.groupdict() # {'id': '12345', 'amount': '99.50'}
4.5 編譯正則:re.compile
當(dāng)同一個(gè)正則需要反復(fù)使用時(shí),預(yù)編譯可以提升性能:
import re
# ========== 預(yù)編譯 ==========
phone_pattern = re.compile(r"(\d{3})-(\d{4})-(\d{4})")
# 之后直接用編譯好的對象調(diào)用方法
text1 = "Call 138-1234-5678"
text2 = "Fax 010-8765-4321"
match1 = phone_pattern.search(text1)
match2 = phone_pattern.search(text2)
# 編譯時(shí)可以加標(biāo)志位
case_insensitive = re.compile(r"hello", re.IGNORECASE) # 忽略大小寫
multiline_mode = re.compile(r"^hello", re.MULTILINE) # ^ 匹配每行行首
dotall_mode = re.compile(r"hello.world", re.DOTALL) # . 匹配換行符
# 常用標(biāo)志位
# re.IGNORECASE / re.I 忽略大小寫
# re.MULTILINE / re.M ^ 和 $ 匹配每行
# re.DOTALL / re.S . 匹配換行符
# re.VERBOSE / re.X 允許寫注釋(復(fù)雜正則推薦)
VERBOSE 模式——讓復(fù)雜正則可讀:
import re
# 普通寫法:難以閱讀
pattern1 = r"(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})\.(?P<ms>\d{3})"
# VERBOSE 寫法:清晰明了 ?
pattern2 = re.compile(r"""
(?P<hour>\d{2}) # 時(shí):2位數(shù)字
: # 分隔符
(?P<min>\d{2}) # 分:2位數(shù)字
: # 分隔符
(?P<sec>\d{2}) # 秒:2位數(shù)字
\. # 小數(shù)點(diǎn)
(?P<ms>\d{3}) # 毫秒:3位數(shù)字
""", re.VERBOSE)
time_text = "14:30:25.123"
match = pattern2.search(time_text)
print(match.groupdict()) # {'hour': '14', 'min': '30', 'sec': '25', 'ms': '123'}
4.6 貪婪 vs 非貪婪
import re
html = "<div>Hello</div><div>World</div>"
# ========== 貪婪匹配(默認(rèn)) ==========
# .* 和 .+ 會(huì)盡可能多地匹配
greedy = re.findall(r"<div>.*</div>", html)
print(greedy) # ['<div>Hello</div><div>World</div>'] 匹配了整個(gè)!??
# ========== 非貪婪匹配(加 ?) ==========
# .*? 和 .+? 會(huì)盡可能少地匹配
non_greedy = re.findall(r"<div>.*?</div>", html)
print(non_greedy) # ['<div>Hello</div>', '<div>World</div>'] ? 兩個(gè)獨(dú)立匹配
# 規(guī)則總結(jié):
# 貪婪: * + ? {n,m} → 盡量多匹配
# 非貪婪:*? +? ?? {n,m}? → 盡量少匹配
4.7 常用正則模式速查
import re
# 郵箱
email_re = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
# 手機(jī)號(中國大陸)
phone_re = r"1[3-9]\d{9}"
# IP 地址
ip_re = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
# URL
url_re = r"https?://[^\s<>\"']+\.[a-zA-Z]{2,}"
# 日期 YYYY-MM-DD
date_re = r"\d{4}-\d{2}-\d{2}"
# 身份證號(18位)
id_re = r"\d{17}[\dXx]"
# 中文字符
chinese_re = r"[\u4e00-\u9fa5]+"
# 快速驗(yàn)證
test_email = "user@example.com"
print(bool(re.fullmatch(email_re, test_email))) # True
5. 字節(jié)串 bytes vs 字符串 str 詳解
5.1 本質(zhì)區(qū)別
┌──────────────────────────────────────────────────┐
│ str (字符串) │
│ - 存儲的是 Unicode 碼點(diǎn)(抽象字符) │
│ - 人能看懂的文本 │
│ - Python 3 中所有字符串默認(rèn)是 str │
│ - 示例: "你好" │
├──────────────────────────────────────────────────┤
│ bytes (字節(jié)串) │
│ - 存儲的是原始字節(jié)(0~255 的整數(shù)序列) │
│ - 機(jī)器能看懂的二進(jìn)制數(shù)據(jù) │
│ - 網(wǎng)絡(luò)傳輸、文件存儲、編解碼的中間形態(tài) │
│ - 示例: b'\xe4\xbd\xa0\xe5\xa5\xbd' │
└──────────────────────────────────────────────────┘
轉(zhuǎn)換關(guān)系:
encode() decode()
str ──────────→ bytes ──────────→ str
編碼 解碼
5.2 創(chuàng)建方式對比
# ========== str 創(chuàng)建 ==========
s1 = "Hello" # 普通字符串
s2 = '你好' # Unicode 字符串
s3 = """多行
字符串""" # 多行字符串
# ========== bytes 創(chuàng)建 ==========
b1 = b"Hello" # 字節(jié)串字面量(只支持 ASCII 字符)
b2 = b'\x48\x65\x6c\x6c\x6f' # 十六進(jìn)制表示
b3 = bytes([72, 101, 108, 108, 111]) # 從整數(shù)列表創(chuàng)建
b4 = "你好".encode("utf-8") # 從字符串編碼
# ?? bytes 字面量只能包含 ASCII 字符
# b"你好" # SyntaxError!
# 必須通過 encode 創(chuàng)建含中文的 bytes
# ========== bytearray(可變字節(jié)串) ==========
ba = bytearray(b"Hello")
ba[0] = 74 # 可修改!bytearray 是可變的
print(ba) # bytearray(b'Jello')
5.3 操作對比
s = "Hello"
b = b"Hello"
# ========== 相同的操作 ==========
print(len(s), len(b)) # 5 5
print(s[0], b[0]) # H 72 ?? str 索引返回字符,bytes 索引返回整數(shù)!
print(s[1:3], b[1:3]) # el b'el' 切片都返回同類型
print(s + " World", b + b" World") # 拼接
print(s * 2, b * 2) # 重復(fù)
# ========== 不同的操作 ==========
# 索引類型不同
print(type(s[0])) # <class 'str'>
print(type(b[0])) # <class 'int'> ?? 關(guān)鍵區(qū)別!
# 遍歷
for ch in "ABC":
print(ch) # A B C → 字符
for byte in b"ABC":
print(byte) # 65 66 67 → 整數(shù)
# 包含判斷
print("H" in "Hello") # True str 中判斷字符
print(72 in b"Hello") # True bytes 中判斷整數(shù)
print(b"H" in b"Hello") # True bytes 中也可以判斷字節(jié)串
# ?? 不能混合操作
# "Hello" + b" World" # TypeError!
# "Hello" == b"Hello" # False 類型不同,永不相等
5.4 編碼深入:UTF-8 vs GBK vs ASCII
text = "你好A"
# ========== 不同編碼對比 ==========
utf8_bytes = text.encode("utf-8") # b'\xe4\xbd\xa0\xe5\xa5\xbdA' 6字節(jié)
gbk_bytes = text.encode("gbk") # b'\xc4\xe3\xba\xc3A' 5字節(jié)
print(f"UTF-8: {utf8_bytes} 長度: {len(utf8_bytes)}")
print(f"GBK: {gbk_bytes} 長度: {len(gbk_bytes)}")
# 編碼規(guī)則:
# UTF-8: 中文3字節(jié),ASCII 1字節(jié)(變長編碼,互聯(lián)網(wǎng)標(biāo)準(zhǔn))?
# GBK: 中文2字節(jié),ASCII 1字節(jié)(中文 Windows 傳統(tǒng)編碼)
# ASCII: 只支持英文,1字節(jié)(0-127)
# ========== 查看字符的 Unicode 碼點(diǎn) ==========
print(ord("你")) # 20320 Unicode 碼點(diǎn)
print(ord("A")) # 65
print(chr(20320)) # "你" 碼點(diǎn)轉(zhuǎn)字符
print(chr(65)) # "A"
# ========== 實(shí)際場景 ==========
# 場景1:判斷文件編碼
def detect_file_encoding(filepath):
"""檢測文件編碼并讀取"""
with open(filepath, "rb") as f: # 二進(jìn)制模式讀取
raw = f.read(4096) # 讀取前4KB
import chardet
result = chardet.detect(raw)
encoding = result["encoding"]
with open(filepath, "r", encoding=encoding) as f:
return f.read()
# 場景2:網(wǎng)絡(luò)數(shù)據(jù)
import json
data = {"name": "yance", "msg": "你好"}
json_bytes = json.dumps(data, ensure_ascii=False).encode("utf-8")
# 發(fā)送 json_bytes 到網(wǎng)絡(luò)...
received = json_bytes.decode("utf-8")
parsed = json.loads(received)
# 場景3:大小計(jì)算
msg = "Hello你好"
print(f"字符數(shù): {len(msg)}") # 7 (5個(gè)英文字母 + 2個(gè)中文字)
print(f"UTF-8 字節(jié)數(shù): {len(msg.encode('utf-8'))}") # 11 (5×1 + 2×3)
print(f"GBK 字節(jié)數(shù): {len(msg.encode('gbk'))}") # 9 (5×1 + 2×2)
5.5 str / bytes / bytearray 速查對比
| 特性 | str | bytes | bytearray |
|---|---|---|---|
| 可變性 | ? 不可變 | ? 不可變 | ? 可變 |
| 字面量 | "hello" | b"hello" | 無 |
| 索引返回 | str (字符) | int (0-255) | int (0-255) |
| 中文支持 | ? | ? (需編碼) | ? (需編碼) |
| 編碼方法 | .encode() | .decode() | .decode() |
| 網(wǎng)絡(luò)傳輸 | ? 需編碼 | ? | ? |
| 字典 key | ? | ? | ? (不可哈希) |
| 典型場景 | 文本處理 | 網(wǎng)絡(luò)I/O、文件I/O | 需修改的二進(jìn)制數(shù)據(jù) |
6. 實(shí)操 Demo:日志解析器(正則實(shí)戰(zhàn))
6.1 需求描述
給定一段 Nginx 風(fēng)格的訪問日志,要求解析出每條日志的結(jié)構(gòu)化數(shù)據(jù):
192.168.1.100 - - [30/May/2026:10:15:30 +0800] "GET /api/users HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" 10.0.0.1 - admin [30/May/2026:10:16:45 +0800] "POST /api/login HTTP/1.1" 401 56 "-" "curl/7.68.0" 172.16.0.50 - - [30/May/2026:10:17:12 +0800] "GET /static/logo.png HTTP/1.1" 304 0 "https://example.com/home" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
需要提?。篒P、用戶、時(shí)間、請求方法、請求路徑、協(xié)議、狀態(tài)碼、響應(yīng)大小、來源頁、UA。
6.2 完整實(shí)現(xiàn)
"""
日志解析器 —— Python 字符串與正則實(shí)戰(zhàn)
功能:解析 Nginx 訪問日志,生成統(tǒng)計(jì)報(bào)告
"""
import re
from collections import Counter, defaultdict
from dataclasses import dataclass, field
from typing import Optional
# ==================== 數(shù)據(jù)模型 ====================
@dataclass
class LogEntry:
"""單條日志記錄"""
ip: str
user: str
datetime: str
method: str
path: str
protocol: str
status: int
size: int
referer: str
user_agent: str
@dataclass
class LogReport:
"""日志統(tǒng)計(jì)報(bào)告"""
total_requests: int = 0
status_counter: Counter = field(default_factory=Counter)
method_counter: Counter = field(default_factory=Counter)
ip_counter: Counter = field(default_factory=Counter)
path_counter: Counter = field(default_factory=Counter)
total_bytes: int = 0
entries: list = field(default_factory=list)
# ==================== 正則模式 ====================
# 使用 VERBOSE 模式,讓正則可讀
NGINX_LOG_PATTERN = re.compile(r"""
^(?P<ip>\S+) # IP 地址
\s+-\s+ # 分隔符: -
(?P<user>\S+) # 用戶(- 表示匿名)
\s+\[ # 分隔符: [
(?P<datetime>[^\]]+) # 時(shí)間:30/May/2026:10:15:30 +0800
\]\s+" # 分隔符: ] "
(?P<method>GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS) # 請求方法
\s+ # 空格
(?P<path>\S+) # 請求路徑
\s+ # 空格
(?P<protocol>HTTP/[\d.]+) # 協(xié)議版本
"\s+ # 分隔符: "
(?P<status>\d{3}) # 狀態(tài)碼
\s+ # 空格
(?P<size>\d+) # 響應(yīng)大小
\s+" # 分隔符: "
(?P<referer>[^"]*) # 來源頁
"\s+" # 分隔符: " "
(?P<user_agent>[^"]*) # User-Agent
".*$ # 結(jié)尾
""", re.VERBOSE)
# ==================== 解析器 ====================
class LogParser:
"""Nginx 日志解析器"""
def __init__(self, pattern: re.Pattern = NGINX_LOG_PATTERN):
self.pattern = pattern
def parse_line(self, line: str) -> Optional[LogEntry]:
"""解析單行日志"""
line = line.strip()
if not line:
return None
match = self.pattern.match(line)
if not match:
print(f"[WARN] 無法解析: {line[:80]}...")
return None
d = match.groupdict()
return LogEntry(
ip=d["ip"],
user=d["user"] if d["user"] != "-" else "anonymous",
datetime=d["datetime"],
method=d["method"],
path=d["path"],
protocol=d["protocol"],
status=int(d["status"]),
size=int(d["size"]),
referer=d["referer"] if d["referer"] != "-" else "",
user_agent=d["user_agent"],
)
def parse_file(self, filepath: str) -> LogReport:
"""解析日志文件"""
report = LogReport()
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
entry = self.parse_line(line)
if entry:
report.entries.append(entry)
report.total_requests += 1
report.status_counter[entry.status] += 1
report.method_counter[entry.method] += 1
report.ip_counter[entry.ip] += 1
report.path_counter[entry.path] += 1
report.total_bytes += entry.size
return report
def parse_string(self, log_text: str) -> LogReport:
"""解析日志字符串(用于測試)"""
report = LogReport()
for line in log_text.strip().split("\n"):
entry = self.parse_line(line)
if entry:
report.entries.append(entry)
report.total_requests += 1
report.status_counter[entry.status] += 1
report.method_counter[entry.method] += 1
report.ip_counter[entry.ip] += 1
report.path_counter[entry.path] += 1
report.total_bytes += entry.size
return report
# ==================== 報(bào)告生成 ====================
class ReportPrinter:
"""格式化輸出統(tǒng)計(jì)報(bào)告"""
@staticmethod
def print_report(report: LogReport):
"""輸出完整報(bào)告"""
print("=" * 60)
print("?? Nginx 日志分析報(bào)告")
print("=" * 60)
# 總覽
print(f"\n?? 總覽")
print(f" 總請求數(shù): {report.total_requests}")
print(f" 總流量: {report.total_bytes:,} bytes "
f"({report.total_bytes / 1024:.1f} KB)")
# 狀態(tài)碼分布
print(f"\n?? 狀態(tài)碼分布")
for status, count in report.status_counter.most_common():
bar = "█" * (count * 40 // report.total_requests)
print(f" {status}: {count:>4} {bar}")
# 請求方法分布
print(f"\n?? 請求方法分布")
for method, count in report.method_counter.most_common():
print(f" {method:<8}: {count}")
# TOP 5 IP
print(f"\n?? TOP 5 訪問 IP")
for ip, count in report.ip_counter.most_common(5):
print(f" {ip:<18}: {count} 次")
# TOP 5 路徑
print(f"\n?? TOP 5 訪問路徑")
for path, count in report.path_counter.most_common(5):
print(f" {path:<30}: {count} 次")
print("\n" + "=" * 60)
@staticmethod
def search_entries(report: LogReport, **kwargs) -> list[LogEntry]:
"""按條件篩選日志條目"""
results = report.entries
for key, value in kwargs.items():
results = [e for e in results if getattr(e, key) == value]
return results
# ==================== 主程序 ====================
def main():
"""主函數(shù):演示完整流程"""
# 模擬日志數(shù)據(jù)
sample_log = """
192.168.1.100 - - [30/May/2026:10:15:30 +0800] "GET /api/users HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
10.0.0.1 - admin [30/May/2026:10:16:45 +0800] "POST /api/login HTTP/1.1" 401 56 "-" "curl/7.68.0"
172.16.0.50 - - [30/May/2026:10:17:12 +0800] "GET /static/logo.png HTTP/1.1" 304 0 "https://example.com/home" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
192.168.1.100 - - [30/May/2026:10:18:00 +0800] "GET /api/users HTTP/1.1" 200 2456 "https://example.com/users" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
10.0.0.1 - admin [30/May/2026:10:18:30 +0800] "POST /api/login HTTP/1.1" 200 234 "-" "curl/7.68.0"
192.168.1.200 - - [30/May/2026:10:19:05 +0800] "DELETE /api/users/5 HTTP/1.1" 403 89 "https://example.com/admin" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
172.16.0.50 - - [30/May/2026:10:19:30 +0800] "GET /static/style.css HTTP/1.1" 200 8765 "https://example.com/home" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
192.168.1.100 - - [30/May/2026:10:20:00 +0800] "PUT /api/users/1 HTTP/1.1" 200 567 "https://example.com/users/1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
10.0.0.2 - - [30/May/2026:10:20:15 +0800] "GET /api/products HTTP/1.1" 200 4532 "https://example.com/shop" "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X)"
192.168.1.100 - - [30/May/2026:10:21:00 +0800] "GET /api/users HTTP/1.1" 500 120 "https://example.com/users" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
"""
# 1. 解析日志
parser = LogParser()
report = parser.parse_string(sample_log)
# 2. 輸出報(bào)告
ReportPrinter.print_report(report)
# 3. 條件篩選示例
print("\n?? 篩選示例:狀態(tài)碼為 200 的請求")
success_entries = ReportPrinter.search_entries(report, status=200)
for entry in success_entries:
print(f" {entry.ip} → {entry.method} {entry.path} ({entry.status})")
print("\n?? 篩選示例:來自 192.168.1.100 的請求")
ip_entries = ReportPrinter.search_entries(report, ip="192.168.1.100")
for entry in ip_entries:
print(f" {entry.method} {entry.path} → {entry.status}")
# 4. 字符串操作技巧演示
print("\n" + "=" * 60)
print("?? 日志解析中用到的字符串技巧")
print("=" * 60)
line = '192.168.1.100 - - [30/May/2026:10:15:30 +0800] "GET /api/users HTTP/1.1" 200 1234'
# 技巧1:split 快速提取
ip = line.split()[0]
print(f"split 取 IP: {ip}")
# 技巧2:strip 去除引號
raw_request = '"GET /api/users HTTP/1.1"'
request = raw_request.strip('"')
print(f"strip 去引號: {request}")
# 技巧3:正則命名分組提取
time_match = re.search(r"\[(?P<time>[^\]]+)\]", line)
if time_match:
print(f"正則提時(shí)間: {time_match.group('time')}")
# 技巧4:f-string 格式化輸出
status = 200
size = 1234
print(f"格式化輸出: status={status:03d}, size={size:,} bytes")
# 技巧5:join 拼接路徑
segments = ["api", "v2", "users", "123"]
url_path = "/" + "/".join(segments)
print(f"join 拼路徑: {url_path}")
if __name__ == "__main__":
main()
6.3 運(yùn)行結(jié)果
============================================================ ?? Nginx 日志分析報(bào)告 ============================================================ ?? 總覽 總請求數(shù): 10 總流量: 18,053 bytes (17.6 KB) ?? 狀態(tài)碼分布 200: 6 ████████████████████████ 401: 1 ████ 304: 1 ████ 403: 1 ████ 500: 1 ████ ?? 請求方法分布 GET : 6 POST : 2 PUT : 1 DELETE : 1 ?? TOP 5 訪問 IP 192.168.1.100 : 4 次 10.0.0.1 : 2 次 172.16.0.50 : 2 次 192.168.1.200 : 1 次 10.0.0.2 : 1 次 ?? TOP 5 訪問路徑 /api/users : 3 次 /api/login : 2 次 /static/logo.png : 1 次 /static/style.css : 1 次 /api/users/5 : 1 次 ============================================================ ?? 篩選示例:狀態(tài)碼為 200 的請求 192.168.1.100 → GET /api/users (200) 192.168.1.100 → GET /api/users (200) 10.0.0.1 → POST /api/login (200) 172.16.0.50 → GET /static/style.css (200) 192.168.1.100 → PUT /api/users/1 (200) 10.0.0.2 → GET /api/products (200) ?? 篩選示例:來自 192.168.1.100 的請求 GET /api/users → 200 GET /api/users → 200 PUT /api/users/1 → 200 GET /api/users → 500 ?? 日志解析中用到的字符串技巧 ============================================================ split 取 IP: 192.168.1.100 strip 去引號: GET /api/users HTTP/1.1 正則提時(shí)間: 30/May/2026:10:15:30 +0800 格式化輸出: status=200, size=1,234 bytes join 拼路徑: /api/v2/users/123
7. 總結(jié)與速查表
7.1 字符串方法速查
| 分類 | 方法 | 說明 | 示例 |
|---|---|---|---|
| 查找 | find() | 返回索引或 -1 | "hello".find("ll") → 2 |
index() | 返回索引或異常 | "hello".index("ll") → 2 | |
count() | 出現(xiàn)次數(shù) | "hello".count("l") → 2 | |
| 替換 | replace() | 替換子串 | "aabb".replace("a","x") → “xxbb” |
| 分割 | split() | 分割為列表 | "a,b,c".split(",") → [‘a’,‘b’,‘c’] |
rsplit() | 從右分割 | "a-b-c".rsplit("-",1) → [‘a-b’,‘c’] | |
splitlines() | 按行分割 | "a\nb".splitlines() → [‘a’,‘b’] | |
join() | 合并為字符串 | ",".join(['a','b']) → “a,b” | |
| 去除 | strip() | 去兩端字符 | " hi ".strip() → “hi” |
lstrip() | 去左端 | " hi ".lstrip() → "hi " | |
rstrip() | 去右端 | " hi ".rstrip() → " hi" | |
| 大小寫 | upper() | 全大寫 | "Hi".upper() → “HI” |
lower() | 全小寫 | "Hi".lower() → “hi” | |
title() | 標(biāo)題格式 | "hi world".title() → “Hi World” | |
capitalize() | 首字母大寫 | "hi".capitalize() → “Hi” | |
swapcase() | 大小寫互換 | "Hi".swapcase() → “hI” | |
| 判斷 | startswith() | 前綴判斷 | "test.py".startswith("test") → True |
endswith() | 后綴判斷 | "test.py".endswith(".py") → True | |
isdigit() | 全是數(shù)字 | "123".isdigit() → True | |
isalpha() | 全是字母 | "abc".isalpha() → True | |
isalnum() | 字母或數(shù)字 | "abc123".isalnum() → True | |
| 對齊 | center() | 居中 | "hi".center(6) → " hi " |
ljust() | 左對齊 | "hi".ljust(6) → "hi " | |
rjust() | 右對齊 | "hi".rjust(6) → " hi" | |
zfill() | 左補(bǔ)零 | "42".zfill(5) → “00042” | |
| 編解碼 | encode() | str→bytes | "你好".encode("utf-8") |
decode() | bytes→str | b'\xe4...'.decode("utf-8") |
7.2 re 模塊 API 速查
| API | 功能 | 返回值 |
|---|---|---|
re.search(pattern, string) | 搜索第一個(gè)匹配 | Match 或 None |
re.match(pattern, string) | 匹配字符串開頭 | Match 或 None |
re.fullmatch(pattern, string) | 完整匹配整個(gè)字符串 | Match 或 None |
re.findall(pattern, string) | 找出所有匹配 | 列表 |
re.finditer(pattern, string) | 迭代器版 findall | 迭代器 |
re.sub(pattern, repl, string) | 替換 | 新字符串 |
re.split(pattern, string) | 正則分割 | 列表 |
re.compile(pattern) | 預(yù)編譯正則 | Pattern 對象 |
7.3 關(guān)鍵要點(diǎn)回顧
- 字符串不可變:所有"修改"操作都返回新字符串,原串不變
- 切片左閉右開:
s[2:5]取索引 2、3、4,不取 5 - f-string 首選:可讀性好、性能優(yōu)、功能強(qiáng)(3.6+)
- 原始字符串 r"":正則和 Windows 路徑必備,避免轉(zhuǎn)義地獄
- bytes vs str:網(wǎng)絡(luò) I/O 用 bytes,文本處理用 str,encode/decode 橋接
- 正則 VERBOSE:復(fù)雜正則一定要用
re.VERBOSE,可讀性 >> 簡潔性 - 非貪婪模式:
.*?是 HTML/XML 提取的標(biāo)配 - 預(yù)編譯:同一正則反復(fù)使用時(shí),
re.compile()提升性能
以上就是Python字符串從入門到精通的實(shí)戰(zhàn)指南的詳細(xì)內(nèi)容,更多關(guān)于Python字符串指南的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PyTorch 如何設(shè)置隨機(jī)數(shù)種子使結(jié)果可復(fù)現(xiàn)
這篇文章主要介紹了PyTorch 設(shè)置隨機(jī)數(shù)種子使結(jié)果可復(fù)現(xiàn)操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-05-05
如何基于Python和Flask編寫Prometheus監(jiān)控
這篇文章主要介紹了如何基于Python和Flask編寫Prometheus監(jiān)控,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Python數(shù)據(jù)結(jié)構(gòu)之遞歸方法詳解
這篇文章主要為大家介紹了遞歸的基本概念以及如何構(gòu)建遞歸程序。通過本章的學(xué)習(xí),大家可以理解遞歸的基本概念,了解遞歸背后蘊(yùn)含的編程思想以及掌握構(gòu)建遞歸程序的方法,需要的可以參考一下2022-04-04
基于python分析你的上網(wǎng)行為 看看你平時(shí)上網(wǎng)都在干嘛
這篇文章主要介紹了基于python分析你的上網(wǎng)行為 看看你平時(shí)上網(wǎng)都在干嘛,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Python實(shí)現(xiàn)XML文件解析的示例代碼
本篇文章主要介紹了Python實(shí)現(xiàn)XML文件解析的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02
Python連接數(shù)據(jù)庫使用matplotlib畫柱形圖
這篇文章主要介紹了Python連接數(shù)據(jù)庫使用matplotlib畫柱形圖,文章通過實(shí)例展開對主題的相關(guān)介紹。具有一定的知識參考價(jià)值性,感興趣的小伙伴可以參考一下2022-06-06

