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