開發
PyCharm Docs
騰訊雲:Python 虛擬環境(pipenv、vnev、conda)一網打盡
pipx
pipx 官網
pipx
— 在孤立環境中安裝和執行 Python 應用程式
安裝
brew install pipx
pipx ensurepath
命令補全
pipx completions # 遵循該命令的指引
Poetry
Poetry
Poetry 是當下熱門的 Python 包管理器。Poetry 注重為專案提供完整的生命週期管理,包括構建、打包、釋出和依賴管理。它的目標是成為 Python 專案的唯一工具。其使用 pyproject.toml
檔案來管理專案的依賴和構建配置。
安裝
pipx install poetry
命令補全
mkdir $ZSH_CUSTOM/plugins/poetry
poetry completions zsh > $ZSH_CUSTOM/plugins/poetry/_poetry
然後,你必須將 poetry
新增到你的 ~/.zshrc
中的 plugins 陣列:
plugins(
poetry
...
)
建立新專案
poetry new poetry-demo
cd poetry-demo
poetry shell
exit
初始化已經存在的專案
cd pre-existing-project
poetry init
安裝依賴
poetry install
啟用虛擬環境
poetry shell
$ exit # 退出虛擬環境
移除虛擬環境
poetry env remove
Basic Usage | Poetry Docs
Pipenv
Pipenv 是 Python 官方推薦的依賴管理工具,旨在簡化 pip 和 virtualenv 的使用。其使用 Pipfile
和 Pipfile.lock
來管理專案的依賴和虛擬環境。
# 安裝
pip3 install --user pipenv # 如果當前使用者不是 root,就使用 --user 選項
不要使用 brew
安裝 pipenv
:
Homebrew installation is discouraged because it works better to install pipenv using pip on macOS.
pipenv install # 為目錄建立新的虛擬環境,並使用目錄中的 Pipfile 或 requirements.txt 安裝依賴
PIPENV_VENV_IN_PROJECT=1 pipenv install --deploy # deploy 會驗證 Pipfile.lock 是不是由對應的 Pipfile 生成的
# 使用映象源安裝
pipenv install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
pipenv --venv # 檢視當前虛擬環境的資訊
pipenv shell # 啟用虛擬環境
pipenv run python main.py # 直接在外部執行虛擬環境命令
exit # 退出虛擬環境
pipenv --rm # 刪除虛擬環境
# 更改映象源
pipenv --pypi-mirror https://pypi.tuna.tsinghua.edu.cn/simple
pipenv lock # 生成 Pipfile.lock
pipenv sync # 安裝 Pipfile.lock 中的依賴
pipenv update # pipenv lock && pipenv sync
pipenv requirements > requirements.txt # 生成 requirements.txt
常用命令一覽:
pipenv --where # 列出本地工程路徑
pipenv --venv # 列出虛擬環境路徑
pipenv --py # 列出虛擬環境的 Python 可執行檔案
pipenv install # 建立虛擬環境
pipenv install [moduel] # 安裝包
pipenv install [moduel] --dev # 安裝包到開發環境
pipenv uninstall[module] # 解除安裝包
pipenv uninstall --all # 解除安裝所有包
pipenv graph # 檢視包依賴
pipenv lock # 生成 lockfile
pipenv run python [pyfile] # 執行 py 檔案
pipenv --rm # 刪除虛擬環境
Official Website
Python Guide CN
Python——pipenv 精心整理教程 | 掘金
擁抱 pipenv - ThomasYoungK | 簡書
Pipenv environment variable LANG is not set! | neldeles's personal blog/portfolio
pip
Remove the pip search command
由於自 2020 年 11 月 14 日以來,PyPI XMLRPC API 持續收到過量的搜尋呼叫,因此 pip search
命令將在不久的將來(撰稿日期 2022.9.26)棄用。目前要想使用 pip search
功能,可以在 PyPI 官網 進行搜尋。
為 Python 專案獨立地配置虛擬環境:Virtual Environments and Packages
python3 -m venv .venv # 在當前專案下新建一個 .venv 資料夾,用於存放虛擬環境
source .venv/bin/activate # 進入虛擬環境
deactivate # 退出虛擬環境
即使沒有啟用虛擬環境,只要執行的是虛擬環境的
Scripts
目錄下的 python 或 pip 可執行程式,依然能達到進入虛擬環境的效果。在 PyCharm 中指定 Python 直譯器為虛擬環境中的直譯器即可進入虛擬環境。
換源
臨時更換映象源
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ some-package
永久更換映象源
在檔案 ~/.pip/pip.conf
中填入以下內容:
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = https://pypi.tuna.tsinghua.edu.cn
Windows 上的相應檔案路徑為 %HOMEPATH%\pip\pip.ini
PIP 配置檔案參考文件
requirements.txt
pipreqs
工具可以透過掃描專案目錄幫助我們生成專案的依賴清單:
pip install pipreqs
pipreqs . # 為當前專案生成依賴清單
也可以使用 pip3 freeze
,該命令將當前虛擬環境中安裝的所有包及其版本號寫入 requirements.txt
檔案。(需要在 venv 環境下執行)
pip freeze > requirements.txt # 生成當前環境的依賴清單
pip install -r requirements.txt # 安裝依賴
可以在 requirements.txt
頂部新增 -i https://pypi.tuna.tsinghua.edu.cn/simple
來指定映象源。
pipinstaller
Installs pip packages on all your installed Python versions (Windows only)
官方文件
# 打包專案
pipinstaller -p . -o ./dist
Practice
進度條
from tqdm import tqdm
progress_bar = tqdm(total=total_num, desc='Progress', unit='kb', unit_scale=True)
for i in range(total_num):
progress_bar.update(1)
progress_bar.close()
雜項
Python 識別符號命名規範
淺複製和深複製
淺複製和深複製
- 淺複製,指的是重新分配一塊記憶體,建立一個新的物件,但裡面的元素是原物件中各個子物件的引用。
- 深複製,是指重新分配一塊記憶體,建立一個新的物件,並且將原物件中的元素,以遞迴的方式,透過建立新的子物件複製到新物件中。
bytes
相當於位元組陣列
b1 = b"ASCII" # ASCII 字元可以直接轉換為 bytes
b2 = bytes("string", encoding="utf-8") # 使用構造方法將指定的字符集轉換為 bytes
b3 = "string".encode("utf-8") # 使用字串自帶的 encode() 方法獲得 bytes
s = b3.decode("utf-8") # bytes 類也有 decode() 方法返回 string
複數
complex = 1 + 2j # 虛部以 j 或 J 作為字尾
高精度計算
import decimal # 十進位制運算
a = decimal.Decimal("10.0")
b = decimal.Decimal("3")
print(a/b)
from fractions import Fraction
print(Fraction(10, 3))
原生字串
r'raw string'
r"raw string"
長字串
'''long string'''
"""long string"""
r'''raw long string'''
字串換行
# 推薦
str = ("str1"
"str2")
# 不推薦
str = "str1\
str2"
型別轉換
Python 型別轉換
int(str)
float(str)
bool(str)
complex(real, [imag])
str(x)
chr(x) # 將 ASCII 碼 x 轉換成對應的字元
ord(c) # 將字元 c 轉換成 ASCII 碼
oct(x) # 將 x 轉換為 8 進位制字串
hex(x) # 將 x 轉換為 16 進位制字串
常用函式
type(obj) # 檢測 obj 的型別
id(obj) # 返回 obj 的地址
dir(obj) # 檢視 obj 中的內容,obj 可省略。
help(obj) # 檢視 obj 的幫助文件
__doc__
屬性:提供某個函式的說明文件
assert 斷言
assert expression # 若表示式值為假,丟擲 AssertionError 錯誤。
邏輯控制
if
if expression:
# TO DO
elif expression:
pass
else:
# TO DO
while
while expression:
# TO DO
else:
# TO DO
for
for var in c:
# TO DO
else:
# TO DO
break
continue
while
和for
後面都可以跟else
match
match http_status:
case 404:
return "Not found"
case 200:
return "OK"
case 418:
return "I'm a teapot"
case _: # 相當於 default
return "Something's wrong with the internet"
運算子
算數運算子與賦值運算子
//
整除
**
冪運算
*
可以用於重複字串:str * 4
別忘了冪運算可以實現開方運算:
16**(1/4)
算數運算子
賦值運算子
is
, is not
:==
用來比較兩個變數的值是否相等,而 is
用來對比兩個變數引用的是否是同一個物件。
邏輯運算子
and
, or
, not
and
和 or
運算子會將其中一個表示式的值作為結果。
三目運算子
max = a if a>b else b
I/O
輸入
str = input("tipmsg") # tipmsg 是提示資訊
輸出
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
print()
函式接受多個輸出內容 value
,可以透過 sep
設定分隔符,end
設定結束符,file
設定輸出檔案,flush
控制輸出快取(一般為 False
)。
f = open("input.txt", "w") # 以寫入模式開啟 input.txt
print('Hello World', file=f)
f.close()
print 格式化輸出
print 格式化輸出
print()
使用的轉換說明符與 C 語言 printf()
類似。
name = "Xiao"
age = 20
print("My name is %s and I'm %d years old." % (name, age))
格式化字串和變數之間用 %
分隔。
跳脫字元
序列
str[1] # 可以使用 0 ~ n-1 的索引訪問序列元素,也可以使用 -n ~ -1 的索引訪問序列元素。
str[start:end:step] # 序列切片,[start, end)
list = [None] * 5 # 序列相乘
in 關鍵字
可以使用 in
關鍵字檢查某元素是否為序列的成員:
str = "c.biancheng.net"
print('c' in str)
還有和 in
功能相反的 not in
關鍵字。
內建函式
len(s)
max(s)
min(s)
list(s) # 將序列轉換為列表
str(s) # 將序列轉換為字串
sum(s) # 計算元素和,元素必須為數字。
sorted(s) # 返回一個排好序的 list
reversed(s) # 返回給定序列的反向迭代器
enumerate(s) # 將序列組合為一個索引序列
sorted()
list
Python 中沒有陣列,但是有功能更加強大的列表。
# 建立列表
l = [1, "2", [3.0]] # 列表可以儲存任意型別
# list() 可以將其他資料型別轉換為列表型別
l = list("Hello") # ['H', 'e', 'e', 'l', 'l', 'o']
# 新增元素
l.append(obj) # 將引數作為整體加入列表
l.extend(obj) # 若引數是列表或元組,將它們包含的元素逐個加入列表。
l.insert(0, obj) # 在指定位置插入元素,將引數視為整體
l3 = l1 + l2
# 刪除元素
del l[0] # 也可以使用負數索引
del l[start:end] # 刪除 [start, end)
l.pop(index) # 若省略索引則刪除最後一個元素
l.remove(val) # 根據元素本身的值進行刪除,只會刪除第一個匹配項,並且必須保證匹配項存在。
l.clear() # 清空列表
# 修改元素
l[0] = 2
l[1:4] = [3.4, 5, 2] # 新賦值元素個數可以不與區間元素個數相同
l[1:6:2] = [0.1, -99, 2] # 但是如果指定步長,則必須相同。
# 查詢元素
# 如果元素不存在,丟擲 ValueError 錯誤。返回 val 的索引值。
l.index(val[,start[,end]])
count(val) # 返回元素在列表中出現的次數
del
刪除的應該是引用變數,實際的記憶體空間並不會馬上被回收。要想讓系統回收這些記憶體,需要使用 gc
庫的 collect()
函式。
import gc
l = [1, 2, 3]
del l
gc.collect()
range 快速初始化數字列表
r1 = range(10)
r2 = range(0, 10) # 返回 [0, 10) 的 range
r3 = range(0, 10, 2) # 設定步長
range()
返回的並不是list
型別,返回的就是range
型別。如果要得到list
型別,需要使用list()
函式。
序列解包
Python 可以以這種形式直接將列表/元組中的元素賦給對應的變數:
lst = [1, 2, 3]
a1, a2, a3 = lst
tuple 元組
- 元組是不可變序列;
- 元組可以在對映和集合中當作“鍵”來使用;
t1 = (1, 2, 3) # 元素可以是任意型別;小括號可以省略。
t1 = 1, 2, 3
t2 = ("str",) # 如果元組中只有一個字串,必須在字串後面加一個逗號。
t3 = tuple(obj) # 將其他資料型別轉化為元組型別
dict 字典
相當於 C++ 中的 map
d1 = {key1: val1, key2: val2} # val 可以是任意資料型別,key 只要滿足唯一和不可變即可。
d2 = dict.fromkeys(list, value=None) # 使用 list 作為鍵的列表,value 為每個鍵對應的值。
d3 = dict(str1=val1, str2=val2) # str 表示字串型別的鍵(不帶引號)
s = [['two', 2], ['one', 1], ['three', 3]]
d4 = dict(s) # 向 dict() 函式傳入列表或元組,而它們中的元素又各自是包含 2 個元素的列表或元組,其中第一個元素作為鍵,第二個元素作為值。
keys = ['one', 'two', 'three']
vals = [1, 2, 3]
a = dict(zip(keys, vals))
基本操作
# 訪問元素
d[key] # 若 key 不存在,則丟擲異常。
d.get(key[,default]) # 不會丟擲異常,可以指定查詢失敗時的預設返回值。
# 增加/修改元素
d[key] = val # 直接給不存在的鍵賦值;當鍵已存在時,覆蓋對應的值。
# 刪除元素
del d[key]
# 判斷字典中是否存在指定的鍵
print(key in d)
常用操作
獲取字典的鍵、值、鍵值對
d.keys() # 返回 dict_keys
d.values() # 返回 dict_values
d.items() # 返回 dict_items
這些方法的返回值不是常見的列表或元組型別,如果想使用返回的資料,一般有下面兩種方法:
- 使用
list()
函式 - 使用
for in
迴圈
for k, v in d.items():
print(k + ": " + v)
copy
copy()
方法只會對最表層的鍵值對進行深複製。
d1 = {'one': 1, 'two': 2, 'three': [1, 2, 3]}
d2 = d1
d1['four'] = 4 # 不影響 d2
d1['three'].remove(1) # 影響 b2
其他
d2.update(d1) # 使用 d1 更新 d2 ,不存在的鍵值對加入,重複的鍵值對覆蓋。
d.pop(key) # 刪除指定的鍵值對
d.popitem() # 刪除最後的鍵值對
d.setdefault(key, defval) # key 不存在時,設定 key-defval 鍵值對並返回 defval;key 存在時,返回其對應的 val 。
使用字典格式化字串
set 集合
set 相當於只有鍵,沒有值的 map 。
s1 = {1, 2, 3}
s2 = set(iteration) # 將字串、列表、元組等可迭代物件轉換成集合
{}
會被直譯器當作空字典,而不是空集合。- 由於 Python 中的 set 集合是無序的,所以每次輸出時元素的排序順序可能都不相同。
基本操作
s.add(obj) # 只能新增不可變資料
s.remove(obj) # 若元素不存在,則丟擲 KeyError 錯誤。
s1 & s2 # 取交集
s1 | s2 # 取並集
s1 - s2 # 取差集
s1 ^ s2 # 取對稱差集
取對稱差集:取集合 A 和 B 中不屬於 A & B 的元素
set 方法
frozenset
字串
str1 = "string 1" "string 2" # 拼接字串常量
str2 = s1 + s2 # 拼接字串變數
str(obj) # 將 obj 轉換為字串
repr(obj) # 將 obj 轉換為 Python 字串的表示式形式
s.encode("gbk") # 獲取編碼後得到的 bytes
encode() 和 decode() 方法
常用方法
# 分割字串
s.split(sep[,maxsplit]) # sep:分隔符,預設為 None ,表示所有空白符;maxsplit 表示分割次數(返回的列表中最多有 maxsplit + 1 個元素),分割後剩餘的部分不會截斷,而是一起放到返回的 list 中。
s.split(maxsplit=-1) # 如果不指定 sep 引數,則必須指定 maxsplit;maxsplit=-1 表示分割次數沒有限制。
# 連線字串
str.join(iterable) # str 是合併時的分隔符,iterable 是合併字串的來源,可以是列表、元組等。
'-'.join(["152", "0950", "3397"])
# 統計子串出現次數
s1.count(s2[,start[,end]])
# 查詢子串
s1.find(s2[,start[,end]]) # 返回 s2 在 s1 中的索引,或者 -1 。
s1.rfind(s2[,start[,end]])
s1.index(s2[,start[,end]]) # 與 find 的區別是,如果查詢失敗,index() 會丟擲異常。
# 文字對齊
# width 是包括 s 本身在內的字串總長度;fillchar 預設為空格。
s.ljust(width[,fillchar]) # 左對齊
s.rjust(width[,fillchar]) # 右對齊
s.center(width[,fillchar]) # 居中
s1.startswith(s2[,start[,end]]) # 檢查 s1 是否以 s2 為開頭
s1.endswith(s2[,start[,end]])
s.title() # 將每個單詞的首字母大寫,其他小寫。
s.lower() # 全部轉換為小寫
s.upper()
# 刪除指定字元(串)
s.strip([chars]) # 刪除 s 左右兩側的指定字元(串)
s.lstrip([chars])
s.rstrip([chars])
如果
sep
引數為None
,則連續的空白符不會對分割結果產生影響。
格式化輸出
format 格式化輸出
使用 {}
和 :
指定佔位符
print("貨幣形式:{:,d}".format(1000000))
print("科學計數法:{:E}".format(1200.12))
print("100 的十六進位制:{:#x}".format(100))
print("0.01 的百分比表示:{:.0%}".format(0.01))
推導式
使用推導式可以快速生成列表、元組、字典以及集合型別的資料,因此推導式又可細分為列表推導式、元組推導式、字典推導式以及集合推導式。
列表推導式的語法格式:
[表示式 for 迭代變數 in 可迭代物件 [if 條件表示式]]
其中,[if 條件表示式]
可以省略。
# 列表推導式
[x**2 for x in range(1, 10)] # 1 到 9 的平方列表
[x**2 for x in range(1, 10) if x % 2 == 0] # 1 到 9 的偶數平方列表
[(x, y) for x in range(1, 6) for y in range(1, 5)] # 可以使用多個迴圈
# 元組推導式
(x**2 for x in range(1, 10)) # 用法和列表推導式相同
# 字典推導式
{key:len(key) for key in l} # 使用列表 l 中的元素作為 key ,key 的長度作為 value 。
# 集合推導式
{x**2 for x in range(1, 10)}
元組推導式生成的結果並不是 tuple
,而是 generator
。在遍歷過 generator
物件後其中的元素將不復存在。
a = (x for x in range(1, 10)) # 透過元組推導式獲得一個 generator
如果想要使用元組推導式獲得新元組或新元組中的元素,有以下三種方式:
- 使用
tuple()
建構函式
print(tuple(a))
- 使用 for 迴圈遍歷 generator 物件
for i in a:
print(i, end=' ')
- 使用
__next__()
方法遍歷 generator 物件
print(a.__next__())
print(a.__next__())
zip 函式
zip()
可以將多個序列按照對應位置順序重組為一個個新的元組。當序列元素個數不一致時,取最短的那個。
zip(iterable, ...)
zip()
函式返回的是一個 zip()
物件,可以遍歷 generator 的方法來訪問。
collections 模組
import collections
dq = deque()
函式
def func():
'''
這裡可以編寫說明文件
'''
# TO DO
return
# 獲得說明文件
help(func)
print(func.__doc__)
在傳遞引數時,如果實參型別為不可變型別 (字串、數字、元組),則使用值傳遞;若實參型別為可變型別 (列表、字典),則使用引用傳遞。其原因是在 Python 中可變型別是引用資料型別,在傳參時實際上傳的是引用,本質上還是值傳遞。
因此,如果需要讓函式修改某些資料,則可以透過把這些資料包裝成列表等可變物件,然後在函式中修改列表的方式來完成。
關鍵字引數
def func(n1, n2):
print(n1)
print(n2)
func(1, 2) # 使用位置引數
func(n2=2, n1=1) # 使用關鍵字引數
func(1, n2=2) # 混合傳參,關鍵字引數必須位於所有位置引數之後。
引數預設值
def func(arg1, arg2, arg3=3): # 有預設值的形參必須放在最後
pass
print(func.__defaults__) # 可以透過函式的 `__defaults__` 屬性檢視函式的引數預設值
可變引數
# 元組引數
def func(home, *args) # 在位置引數接收實參後,args 將剩下的所有非關鍵字引數以元組的形式接收。
def func(*args, home) # 元組形式的可變引數不一定要放在最後,但此時必須以關鍵字引數的形式指定位置引數 home 。
# 字典引數
def func(home, **args) # args 接收所有以關鍵字引數賦值的實參,此時 args 必須放在最後。
可變引數的預設值是空元組/空字典,因此可以不給可變引數傳值。
逆向引數收集
可變引數將多個引數儲存到列表/元組中,這個過程稱為引數收集。反過來,將列表、元組、字典作為函式引數,Python 可以將其拆分,把其中的元素按照次序分給函式中的各個形參,這個過程叫做逆向引數收集。
和可變引數的規則類似,傳入列表或元組時,要在其名稱前加一個 *
,傳入字典時,要在其名稱前加一個 **
。
def func(arg1, arg2, arg3):
pass
args = [1, 2, 3]
func(*args) # 列表,以位置引數的方式傳參。
args = {"arg1": 1, "arg2": 2, "arg3": 3}
func(**args) # 字典,以關鍵字引數的方式傳參。
偏函式
簡單的理解偏函式,它是對原始函式的二次封裝,是將現有函式的部分引數預先繫結為指定值,從而得到一個新的函式,該函式就稱為偏函式。相比原函式,偏函式具有較少的可變引數,從而降低了函式呼叫的難度。
from functools import partial
def func1(arg1, arg2):
pass
func2 = partial(func1, arg1 = 1) # 定義偏函式,其封裝了 func1() ,併為 arg1 設定了預設引數。
func2(arg2 = 2) # 這裡必須用關鍵字引數的形式給 arg2 傳參,否則 Python 將嘗試將引數傳給 arg1 。
變數作用域
在函式內定義全域性變數
def func():
global var # 在使用 global 關鍵字修飾變數名時,不能給變數賦初值。
獲取指定作用域中的變數
globals() # 返回一個包含所有全域性變數的字典
globals()['var1'] = 1 # 可以透過該字典訪問或修改指定變數
locals() # 返回一個包含當前作用域內所有變數的字典
print(locals()['var1']) # locals() 返回的字典只能訪問變數,無法用來修改變數的值。
vars(obj) # 返回 obj 物件範圍內所有變數組成的字典。
如果要在函式內操作全域性變數,有以下兩種方法:
- 透過
globals()
函式
var = 1
def func():
print(globals()['var']) # 訪問全域性變數 var
var = "new var" # 定義一個新的區域性變數 var
- 使用
global
語句宣告全域性變數
var = 1
def func():
global var
print(var)
var = "same var" # 對全域性變數 var 賦值
類
class Student:
name = "Xiao"
age = 20
# 建構函式
def __init__(self, _name):
name = _name
def func(self, msg):
print(msg)
stu = Student("Li Xiao")
stu.money = 999_999_999 # 可以給類物件動態新增/刪除變數
del stu.money