
答案: 修改全局變量的時候, 需要區(qū)分可變與不可變這兩種類型, 其中不可變類型在函數(shù)內(nèi)部進(jìn)行修改的時候, 必須使用關(guān)鍵字來聲明, 然而可變類型, 比如列表、字典, 只需要直接去修改內(nèi)容就可以了, 不需要使用關(guān)鍵字聲明要是對可變類型重新進(jìn)行賦值的話, 那么仍然是需要使用關(guān)鍵字聲明的。為了避免出現(xiàn)副作用以及利于維護(hù), 推薦采用模塊級變量、類封裝或者函數(shù)參數(shù)返回值等方式來管理狀態(tài), 以此提升代碼的可讀性以及可維護(hù)性。在函數(shù)內(nèi)部中對相關(guān)內(nèi)容進(jìn)行全局變量的修改, 其主要關(guān)鍵在于能否清晰明確, 到底是在函數(shù)內(nèi)部創(chuàng)建了一個與全局變量同名的局部變量, 還是切實(shí)想要去操作外部的那個全局變量。對于簡單類型比如數(shù)字、字符串這類, 在此情形下, 你必須要明確地去使用。global關(guān)鍵字, 而針對可變對象像列表、字典這類, 要是你僅僅改動其包含的內(nèi)容, 并非再次進(jìn)行賦值, 通常來講能夠直接去操作, 并不需要。global。解決方案要修改中的全局變量主要有兩種場景和對應(yīng)的處理方式1. 使用global關(guān)鍵字修改不可變類型或重新綁定可變類型當(dāng)我們打算于函數(shù)內(nèi)部去修改一個在全局之中定義的變量之際, 特別是當(dāng)此變量屬于不可變類型像整數(shù)、字符串、元組之時, 又或者你期望把一個全局的可變類型變量重新指向一個全然新鮮的對象之時, 就一定要明確地告知解釋器, 我們所引用的并非一個局部變量, 而是那個全局變量。這便是。global關(guān)鍵字的用武之地。比如有一個全局計數(shù)器count 0 def increment_global_count(): global count # 聲明我們要操作的是全局的count count 1 print(f函數(shù)內(nèi)部修改后{count}) print(f初始全局變量count{count}) increment_global_count() print(f函數(shù)調(diào)用后全局變量count{count}) # 如果不加global會怎樣 def try_to_increment_without_global(): # count count 1 # 這行會報錯因?yàn)镻ython會認(rèn)為你在創(chuàng)建一個局部count # 但在創(chuàng)建前又試圖讀取它 count 100 # 這行不會報錯但它創(chuàng)建了一個新的局部變量count與全局的無關(guān) print(f函數(shù)內(nèi)部局部count{count}) print(\n嘗試不加global的情況) try_to_increment_without_global() print(f函數(shù)調(diào)用后全局變量count未受影響{count})在這個例子中try_to_increment_without_global函數(shù)內(nèi)部的count 100創(chuàng)建了一個全新的局部變量全局的count絲毫不受影響。而increment_global_count函數(shù)通過global count明確指出它要操作的就是全局作用域中的那個count2. 直接修改可變?nèi)肿兞康膬?nèi)容針對列表list、字典dict或者自定義對象這類可變數(shù)據(jù)類型, 要是你僅僅是想對它們內(nèi)部的元素或者屬性予以修改, 而非把全局變量名重新綁定到一個全新的對象之上, 那么你用不著去使用。global操作的并非變量名, 而是變量所指向的那個對象本身, 這就是關(guān)鍵字相關(guān)情況的緣故。my_list [1, 2, 3] my_dict {a: 1, b: 2} def modify_global_mutable_objects(): my_list.append(4) # 直接修改列表內(nèi)容 my_dict[c] 3 # 直接修改字典內(nèi)容 print(f函數(shù)內(nèi)部修改后列表{my_list}) print(f函數(shù)內(nèi)部修改后字典{my_dict}) print(f初始全局列表{my_list}) print(f初始全局字典{my_dict}) modify_global_mutable_objects() print(f函數(shù)調(diào)用后全局列表{my_list}) print(f函數(shù)調(diào)用后全局字典{my_dict}) # 但如果你想重新賦值仍然需要global def reassign_global_list(): global my_list # 聲明要重新綁定全局的my_list my_list [5, 6, 7] # 將全局my_list指向一個新的列表對象 print(f函數(shù)內(nèi)部重新賦值后列表{my_list}) print(\n嘗試重新賦值全局列表) reassign_global_list() print(f函數(shù)調(diào)用后全局列表{my_list})對于區(qū)分這兩種情況, 以我的想法來看, 它是關(guān)鍵, 能幫助人理解變量作用域以及對象引用。許多剛開始學(xué)習(xí)的人中, 在這個地點(diǎn)會表現(xiàn)出困惑, 產(chǎn)生一種行為好像帶有“不一致”之感, 然而實(shí)際上, 那背后存在一套頗為清晰明了的嚴(yán)謹(jǐn)邏輯。為什么函數(shù)內(nèi)部直接賦值無法修改全局變量舉個例子你可能寫過這樣的代碼x 10 # 全局變量 def func(): x 5 # 局部變量 print(f函數(shù)內(nèi)部的x: {x}) func() print(f函數(shù)外部的x: {x})運(yùn)行這段代碼你會發(fā)現(xiàn)函數(shù)內(nèi)部打印的是5而函數(shù)外部打印的仍然是10。這并不是說“看不到”全局的x而是它在函數(shù)內(nèi)部遇到x 5當(dāng)時, 出于要防止不小心出現(xiàn)的副作用side的目的, 故而決定去選擇創(chuàng)建一個全新的局部。x這樣做之后, 函數(shù)呈現(xiàn)出更為獨(dú)立以及可預(yù)測的特性, 它不會毫無根據(jù)的去修改外部狀態(tài), 進(jìn)而使得代碼的耦合度有所降低。我以個人的角度去感覺, 這般的設(shè)計于大多數(shù)的情形之下都是極為明智的, 它迫使開發(fā)者在對全局狀態(tài)作出修改之際必須清晰明了地進(jìn)行聲明借助。global這, 其自身便是一種代碼審查以及設(shè)計約束, 它會提醒你, 說“嘿, 你此刻正在開展一些極有可能對全局造成影響的事情, 務(wù)必要慎重思考”。要是不存在這個機(jī)制, 那么在函數(shù)內(nèi)部肆意改動全局變量, 如此一來代碼的調(diào)試以及維護(hù)著實(shí)會成為一場災(zāi)難。去設(shè)想一下, 在一個大型項(xiàng)目里頭, 隨便哪一個函數(shù)都極有可能悄悄地改動你并不了解的全局變量, 如此這般, 那Bug追蹤起來絕對是一場噩夢。修改全局變量之時, 存在哪些常見的“坑”以及注意事項(xiàng)呢?關(guān)于修改全局變量這件事情, 老實(shí)講, 它屬于那種具有雙刃劍性質(zhì)的情況了。它具備能夠去解決某一部分問題的能力, 可要是不夠小心謹(jǐn)慎的話, 同樣有可能會埋下數(shù)量不少的隱患。有個極為常見的“坑”, 那便是意外出現(xiàn)的副作用以及難以追蹤的Bug。在多個函數(shù)都依賴或者修改同一個全局變量之際, 一個函數(shù)的修改可能會不經(jīng)意間對另一個函數(shù)的行為產(chǎn)生影響, 并且這種影響常常是間接的、難以預(yù)料的。比如說, 倘若是有一個全局的配置字典 , 某個函數(shù)修改了其中一個值 , 跟著另一個函數(shù)在全不知情的狀況下使用了這個被修改的值 , 進(jìn)而導(dǎo)致程序行為出現(xiàn)異常 , 然而卻很難即刻定位到究竟是哪個函數(shù)在何時進(jìn)行了修改。這會讓代碼變得非常脆弱測試起來也異常困難。3.14.23.2025年12月5日發(fā)布的編程語言穩(wěn)定版本是14.2, 它屬于3.14系列的第二個維護(hù)更新, 該版本有18項(xiàng)修復(fù), 著重解決了多進(jìn)程、數(shù)據(jù)類以及正則表達(dá)式等模塊的回歸問題, 還修復(fù)了CVE - 2025 - 12084等安全漏洞, 此版本標(biāo)志著自由線程模式移除GIL正式得到官方支持, 是發(fā)展的重要里程碑。下載除此之外, 可讀性以及維護(hù)性將會大幅度地下降, 函數(shù)應(yīng)當(dāng)盡可能做到“自包含”, 也就是說它的行動僅此取決于輸入?yún)?shù)以及輸出結(jié)果, 然而并不會產(chǎn)生外部能夠看見的副作用, 一旦函數(shù)開始大量依賴并且修改全局變量, 它的行為便不再單單由輸入決定, 而是由“當(dāng)前全局狀態(tài)”來決定, 這致使理解一個函數(shù)的行為變得繁雜, 緣由在于不僅要查看函數(shù)自身內(nèi)部的邏輯, 還得查閱函數(shù)被調(diào)用時外部全局變量的狀態(tài)。對于新加入的開發(fā)者來講, 理解這樣的代碼簡直猶如一場噩夢一般。仍存在的“競態(tài)條件”問題在于, 于多線程或者多進(jìn)程環(huán)境里, 要是多個執(zhí)行流同時試著去修改同一個全局變量, 倘若沒有恰當(dāng)?shù)耐綑C(jī)制, 像是鎖, 那就有可能致使數(shù)據(jù)損壞或者不一致, 這一般屬于比較高級的坑, 不過也是全局變量所帶來的一個嚴(yán)重隱患。那么, 我所給出的提議便是: 盡可能地防止過度使用全局變量。它們的確具備便利性, 然而所付出的代價常常是代碼的復(fù)雜性以及難以預(yù)測性。要是非得使用, 那么也應(yīng)當(dāng)遵照一些最優(yōu)化的做法, 例如。除了global關(guān)鍵字還有哪些更推薦的全局狀態(tài)管理方式在我看來提供了許多比直接使用global能夠以更為優(yōu)雅且更為安全的方式, 去管理應(yīng)用程序的“全局”狀態(tài)的關(guān)鍵字。這些方法一般而言, 能夠在靈活性以及可維護(hù)性之間, 實(shí)現(xiàn)更好的平衡。1. 模塊級變量-Level 這是中一種非常常見且推薦的“全局”狀態(tài)管理方式。在中每個.py所有的各類文件均屬于一個特定的模塊范疇, 于模塊頂層所進(jìn)行定義的變量, 針對此模塊而言就呈現(xiàn)為全局性質(zhì)的, 別的其他模塊能夠借助。import語句來訪問這些變量。# config.py DEBUG_MODE True DATABASE_URL sqlite:///app.db API_KEY your_api_key_here # main.py import config def process_data(): if config.DEBUG_MODE: print(Debug mode is active.) # ... 使用 config.DATABASE_URL 等 process_data() # 也可以修改但通常不推薦直接修改導(dǎo)入的模塊變量 # config.DEBUG_MODE False # print(config.DEBUG_MODE)這般方式所具備的好處是在于, 它會把相關(guān)聯(lián)的全局設(shè)置或者狀態(tài)給封裝在一個獨(dú)立單獨(dú)的模塊當(dāng)中, 致使代碼的結(jié)構(gòu)變得更加清晰。當(dāng)去訪問這些變量的時候, 是需要借助。config.VARIABLE_NAME這清晰地指明了變量的出處, 提升了代碼的可閱讀性, 它相較于分散在各個地方的。global變量要好得多。2. 類和實(shí)例 and 它是用于管理狀態(tài)的極為管用的工具, 你能夠去創(chuàng)建出一個類, 以此來對所有關(guān)聯(lián)的狀態(tài)以及操作進(jìn)行封裝, 該類的實(shí)例能夠當(dāng)作“全局”對象于應(yīng)用程序里進(jìn)行傳遞。class AppConfig: def __init__(self): self.debug_mode True self.database_url sqlite:///app.db self.user_session {} def set_debug_mode(self, mode): self.debug_mode mode # 在應(yīng)用程序啟動時創(chuàng)建配置實(shí)例 app_settings AppConfig() def another_function(): if app_settings.debug_mode: print(Debug mode is on via AppConfig instance.) app_settings.user_session[current_user] Alice another_function() print(app_settings.user_session)這種方式準(zhǔn)許你把狀態(tài)以及修改狀態(tài)的辦法組合到一起來, 給出上佳的。你能夠依據(jù)所需去創(chuàng)立多個配置實(shí)例, 或者保證僅有一個實(shí)例單例模式。經(jīng)由把。app_settings參數(shù)傳遞給函數(shù)時, 函數(shù)需要它, 通過傳遞實(shí)例, 可避免直接訪問全局變量, 進(jìn)而提高函數(shù)獨(dú)立性。3. 函數(shù)參數(shù)和返回值這是最為“特別”, 同時也是最為值得推薦的方式, 特別是在函數(shù)式編程這一范式之中。倘若讓函數(shù)去對全局變量做修改, 倒不如讓函數(shù)去接收那些必要的參數(shù), 接著返回經(jīng)由修改之后的全新的值或者結(jié)果。# 不推薦的全局變量修改 # current_balance 100 # def deposit(amount): # global current_balance # current_balance amount # 推薦的方式 def deposit(current_balance, amount): return current_balance amount balance 100 balance deposit(balance, 50) print(f新余額: {balance}) # 輸出 150這種方式, 強(qiáng)制函數(shù)僅僅關(guān)聯(lián)于其輸入, 進(jìn)而產(chǎn)生能夠被預(yù)測的輸出, 極大程度上提升了代碼的可測試性, 提升了代碼的可讀性, 還提升了代碼的可維護(hù)性。它規(guī)避了所有全局變量所引發(fā)的副作用問題。盡管有的時候看上去需要傳遞諸多參數(shù), 然而這種顯式的依賴關(guān)系常常比隱式的全局依賴更便于管理。綜合來看雖然global關(guān)鍵字于某些處在特定、被控制的場景之時具備其可以發(fā)揮作用的地方, 然而在大多數(shù)的時間里, 我更加傾向于借助模塊、類或者函數(shù)參數(shù)去對狀態(tài)予以管理。這樣做不但能夠使得代碼變得更加穩(wěn)固強(qiáng)健, 而且還能夠在團(tuán)隊(duì)進(jìn)行協(xié)作之際減少諸多并非必要的困擾麻煩。免費(fèi)學(xué)習(xí)筆記深入立即使用在學(xué)習(xí)筆記中你將探索 的核心概念和高級技巧