HOWTO · Python

在 Python 中將字串轉換為變數名

在本文中,我們將討論在 Python 中將字串值轉換為變數名的各種方法。

本頁內容

Python 不會把字串的值當作一般變數指定運算左側的名稱。若要在執行期間建立或存取名稱,請選擇應保存該名稱的命名空間:模組層級變數使用 globals()、檢視區域名稱使用 locals()、產生的原始碼使用 exec()、物件屬性使用 setattr();如果這些名稱其實只是資料,則使用字典。

注意:動態變數名可能會隱藏相依關係、汙染命名空間,並在程式讀取從未建立的名稱時產生 NameError。對於正式環境軟體而言,這通常不是最佳做法;除非確實需要全域變數或物件屬性,否則請優先使用字典。

在 Python 中使用 globals() 和 locals() 將字串轉換為變數名

內建 globals() 函式會傳回目前全域符號表的字典。該字典會將每個全域變數的名稱對應到其值。在模組範圍中,透過這個字典寫入新鍵,就會以該字串為名稱建立真正的全域變數。

執行此範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

def create_global_variable(name, value):
    globals()[name] = value


variable_name = "dynamicGlobalVar"
variable_value = 10

create_global_variable(variable_name, variable_value)
print(dynamicGlobalVar)
10

此函式會將 "dynamicGlobalVar" 作為 name 引數接收,並把 10 存入全域符號表中該鍵之下。後續的 dynamicGlobalVar 運算式之所以有效,是因為模組現在具有一個名稱完全相同的全域變數。若原始碼要以名稱存取,該字串必須是有效的 Python 識別字;否則請透過 globals()[name] 取出。

全域名稱必須先建立才能讀取。如果先前未把 dynamicGlobalVar 加入全域符號表,最後一行會引發 NameError。在實際程式中,寫入時宜使用 variable_name 之類的變數,而不是在程式各處嵌入未經檢查的字串。

使用 locals() 存取區域變數

locals() 函式會傳回代表目前區域符號表的映射。在函式內部,可用來查詢保存在字串中的區域名稱:

def demonstrate_locals():
    temp_var = "Dynamic Content"
    name = "temp_var"
    return locals().get(name)


print(demonstrate_locals())
Dynamic Content

此處的 locals().get(name) 會在函式執行時解析 "temp_var",並傳回既有區域變數的值。使用 .get() 比直接索引該映射更安全,因為當要求的名稱不存在時會傳回 None。

不要依賴 locals()[name] = value 建立函式的區域變數。Python 實作可以最佳化區域變數,而且寫入傳回的映射並不保證會更新直譯器真正的區域綁定。請主要將 locals() 視為查詢與檢視工具;當程式需要可寫入的動態名稱時,改用 globals()、setattr() 或字典。

在 Python 中使用 exec() 將字串轉換為變數名

exec() 函式會執行以字串提供的 Python 原始碼。如果該字串包含指定運算,執行後就會在目前執行內容中建立相對應的變數。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

variable_name = "dynamicVar"
value = 42

exec(f"{variable_name} = {value}")
print(dynamicVar)
42

f-string 會建構原始碼文字 dynamicVar = 42,而 exec() 會執行該指定運算。在模組層級,結果是名為 dynamicVar 的新全域變數。插入非數值時,請使用 repr() 或等效格式,讓產生的原始碼包含有效的 Python 字面值。

exec() 很強大,因為字串不只能包含單一指定運算:它還能執行迴圈、匯入、函式定義或任意呼叫。這種能力也是其最大風險。絕對不要將使用者控制或其他不可信文字傳給 exec();即使是惡意的名稱或值片段,也可能執行有害程式碼。如同 locals(),也不能依賴 exec() 更新已最佳化的函式區域變數,因此這項技巧最適合用於模組範圍或明確的命名空間字典。

在 Python 中使用 setattr() 將字串轉換為變數名

當所需的「變數」其實是物件、類別或模組上的屬性時,setattr() 是直接可用的工具。它接受物件、以字串表示的屬性名,以及要指定的值。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

class Settings:
    pass


settings = Settings()
attribute_name = "theme"
attribute_value = "dark"

setattr(settings, attribute_name, attribute_value)
print(settings.theme)
dark

此呼叫等同於 settings.theme = "dark",差別在於屬性名會在執行期間來自 attribute_name。這對設定物件、記錄、外掛掛接點,以及其他已在設計中包含命名空間物件的地方很有用。

setattr() 不會建立一般的模組或函式變數;它會更新目標物件的屬性命名空間。使用 getattr(settings, attribute_name) 可動態讀取該值,或在需要後備值時使用 getattr(settings, attribute_name, default_value)。

在 Python 中使用字典取代動態變數名

當程式要把值儲存在只有執行期間才知道的名稱下時,字典通常是最清楚的做法。字串仍會是鍵,因此動態名稱集合會保持明確且易於檢視。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

dynamic_vars = {}

var_name = "temperature"
var_value = 23

dynamic_vars[var_name] = var_value
print(dynamic_vars["temperature"])
23

這會建立與名為 temperature 的變數保存 23 相同的對應關係,但不會把名稱加入 Python 命名空間。這些鍵可以被列出、傳給另一個函式、序列化或移除,無需在 globals() 中搜尋意外項目。

字典鍵也不受 Python 識別字規則限制,因此 "daily total" 這類名稱可以作為資料使用。使用 dynamic_vars[var_name] 存取必要鍵;若缺少鍵時應產生後備值而非失敗,則使用 dynamic_vars.get(var_name)。這可避免 NameError 處理,因為程式是在查詢資料結構,而不是解析原始碼層級的變數。

結論

Python 提供多種將執行期字串轉換為可用名稱的方法。globals() 可以透過全域符號表建立真正的模組層級變數。locals() 可以查詢區域名稱,但作為寫入機制並不可靠。exec() 可以執行產生的指定運算,不過其安全與清晰度風險最高。當動態名稱屬於物件或模組時,setattr() 是合適的選擇。

對多數程式而言,字典是最安全也最易維護的選項。它把動態名稱保留為資料、避免汙染 Python 命名空間,並讓名稱不存在時的行為明確化。只有設計確實需要真正的動態變數或屬性時,才應使用它們。