Python 中的引用傳遞:背景和最佳實踐

      網友投稿 1116 2025-04-02

      目錄

      定義按引用傳遞

      對比引用傳遞和值傳遞

      使用傳遞引用結構

      避免重復對象

      返回多個值

      創建條件多返回函數

      在 Python 中傳遞參數

      理解 Python 中的賦值

      探索函數參數

      使用 Python 復制引用傳遞

      最佳實踐:返回和重新分配

      最佳實踐:使用對象屬性

      最佳實踐:使用字典和列表

      結論

      在熟悉 Python 之后,您可能會注意到函數不會像預期的那樣修改參數的情況,尤其是在您熟悉其他編程語言的情況下。某些語言將函數參數作為對現有變量的引用來處理,這稱為通過引用傳遞。其他語言將它們作為獨立值處理,這種方法稱為按值傳遞。

      如果您是一名中級 Python 程序員,希望了解 Python 處理函數參數的特殊方式,那么本教程適合您。您將在 Python 中實現按引用傳遞構造的實際用例,并學習幾個最佳實踐以避免函數參數中的陷阱。

      在本教程中,您將學習:

      通過引用傳遞意味著什么以及為什么要這樣做

      按引用傳遞與按值傳遞和Python 的獨特方法有何不同

      如何函數參數的行為在Python

      如何使用某些可變類型在 Python 中按引用傳遞

      在 Python 中復制引用傳遞的最佳實踐是什么

      定義按引用傳遞

      在深入研究按引用傳遞的技術細節之前,通過將其分解為多個組件來仔細研究該術語本身會很有幫助:

      Pass表示為函數提供參數。

      引用意味著您傳遞給函數的參數是對內存中已存在的變量的引用,而不是該變量的獨立副本。

      由于您為函數提供了對現有變量的引用,因此對該引用執行的所有操作都將直接影響它所引用的變量。讓我們看一些在實踐中如何工作的例子。

      下面,您將看到如何在 C# 中通過引用傳遞變量。請注意在突出顯示的行中使用ref關鍵字:

      using System; // Source: // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters class Program { static void Main(string[] args) { int arg; // Passing by reference. // The value of arg in Main is changed. arg = 4; squareRef(ref arg); Console.WriteLine(arg); // Output: 16 } static void squareRef(ref int refParameter) { refParameter *= refParameter; } }

      可以看到,refParameterofsquareRef()必須用ref關鍵字聲明,調用函數時也必須使用關鍵字。然后參數將通過引用傳入并且可以就地修改。

      Python 沒有ref關鍵字或與之等效的任何東西。如果您嘗試在 Python 中盡可能接近地復制上述示例,那么您將看到不同的結果:

      >>>

      >>> def main(): ... arg = 4 ... square(arg) ... print(arg) ... >>> def square(n): ... n *= n ... >>> main() 4

      在這種情況下,arg變量不會就地更改。Python 似乎將您提供的參數視為獨立值,而不是對現有變量的引用。這是否意味著 Python 按值而不是按引用傳遞參數?

      不完全的。Python 既不是通過引用也不是通過值傳遞參數,而是通過賦值。下面,在更仔細地研究 Python 的方法之前,您將快速探索按值傳遞和按引用傳遞的細節。之后,您將了解一些最佳實踐,以在 Python 中實現等效于按引用傳遞的效果。

      對比引用傳遞和值傳遞

      當您通過引用傳遞函數參數時,這些參數只是對現有值的引用。相反,當您按值傳遞參數時,這些參數將成為原始值的獨立副本。

      讓我們重溫一下 C# 示例,這次不使用ref關鍵字。這將導致程序使用按值傳遞的默認行為:

      using System; // Source: // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters class Program { static void Main(string[] args) { int arg; // Passing by value. // The value of arg in Main is not changed. arg = 4; squareVal(arg); Console.WriteLine(arg); // Output: 4 } static void squareVal(int valParameter) { valParameter *= valParameter; } }

      在這里,您可以看到squareVal()沒有修改原始變量。相反,valParameter是原始變量的獨立副本arg。雖然這與您在 Python 中看到的行為相匹配,但請記住,Python 并不完全按值傳遞。讓我們證明一下。

      Python 的內置id()返回一個整數,表示所需對象的內存地址。使用id(),您可以驗證以下斷言:

      函數參數最初引用與其原始變量相同的地址。

      在函數內重新分配參數會為其提供一個新地址,而原始變量保持不變。

      在下面的例子中,注意 的地址x最初與的地址匹配,n但在重新分配后發生變化,而 的地址n從不改變:

      >>>

      >>> def main(): ... n = 9001 ... print(f"Initial address of n: {id(n)}") ... increment(n) ... print(f" Final address of n: {id(n)}") ... >>> def increment(x): ... print(f"Initial address of x: {id(x)}") ... x += 1 ... print(f" Final address of x: {id(x)}") ... >>> main() Initial address of n: 140562586057840 Initial address of x: 140562586057840 Final address of x: 140562586057968 Final address of n: 140562586057840

      調用時n和的初始地址x相同的increment()事實證明該x參數不是按值傳遞的。否則,n并且x會有不同的內存地址。

      在了解 Python 如何處理參數的細節之前,讓我們先看一下按引用傳遞的一些實際用例。

      使用傳遞引用結構

      通過引用傳遞變量是您可以用來實現某些編程模式的幾種策略之一。雖然很少需要,但通過引用傳遞可能是一個有用的工具。

      在本節中,您將了解按引用傳遞是一種實用方法的三種最常見模式。然后,您將看到如何使用 Python 實現這些模式中的每一個。

      Python 中的引用傳遞:背景和最佳實踐

      避免重復對象

      如您所見,按值傳遞變量將導致創建該值的副本并將其存儲在內存中。在默認為按值傳遞的語言中,您可能會發現按引用傳遞變量會帶來性能優勢,尤其是當變量包含大量數據時。當您的代碼在資源受限的機器上運行時,這一點會更加明顯。

      然而,在 Python 中,這從來都不是問題。您將在下一節中了解原因。

      返回多個值

      按引用傳遞的最常見應用之一是創建一個函數,該函數在返回不同值的同時更改引用參數的值。您可以修改通過引用傳遞的 C# 示例來說明此技術:

      using System; class Program { static void Main(string[] args) { int counter = 0; // Passing by reference. // The value of counter in Main is changed. Console.WriteLine(greet("Alice", ref counter)); Console.WriteLine("Counter is {0}", counter); Console.WriteLine(greet("Bob", ref counter)); Console.WriteLine("Counter is {0}", counter); // Output: // Hi, Alice! // Counter is 1 // Hi, Bob! // Counter is 2 } static string greet(string name, ref int counter) { string greeting = "Hi, " + name + "!"; counter++; return greeting; } }

      在上面的示例中,greet()返回一個問候字符串并修改 的值counter?,F在嘗試在 Python 中盡可能地重現這一點:

      >>>

      >>> def main(): ... counter = 0 ... print(greet("Alice", counter)) ... print(f"Counter is {counter}") ... print(greet("Bob", counter)) ... print(f"Counter is {counter}") ... >>> def greet(name, counter): ... counter += 1 ... return f"Hi, {name}!" ... >>> main() Hi, Alice! Counter is 0 Hi, Bob! Counter is 0

      counter在上面的示例中沒有遞增,因為正如您之前所了解的,Python 無法通過引用傳遞值。那么如何才能獲得與使用 C# 相同的結果呢?

      本質上,C# 中的引用參數不僅允許函數返回值,還允許對附加參數進行操作。這相當于返回多個值!

      幸運的是,Python 已經支持返回多個值。嚴格來說,返回多個值的 Python 函數實際上返回一個包含每個值的元組:

      >>>

      >>> def multiple_return(): ... return 1, 2 ... >>> t = multiple_return() >>> t # A tuple (1, 2) >>> # You can unpack the tuple into two variables: >>> x, y = multiple_return() >>> x 1 >>> y 2

      如您所見,要返回多個值,您可以簡單地使用return關鍵字后跟逗號分隔的值或變量。

      這種技術的武裝,你可以改變return聲明中的greet()從以前的Python代碼同時返回問候和計數器:

      >>>

      >>> def main(): ... counter = 0 ... print(greet("Alice", counter)) ... print(f"Counter is {counter}") ... print(greet("Bob", counter)) ... print(f"Counter is {counter}") ... >>> def greet(name, counter): ... return f"Hi, {name}!", counter + 1 ... >>> main() ('Hi, Alice!', 1) Counter is 0 ('Hi, Bob!', 1) Counter is 0

      那看起來還是不對。盡管greet()現在返回多個值,但它們被打印為tuple,這不是您的意圖。此外,原始counter變量保持在0。

      清理你的輸出,并得到想要的結果,你必須重新分配你的counter每次調用變量greet():

      >>>

      >>> def main(): ... counter = 0 ... greeting, counter = greet("Alice", counter) ... print(f"{greeting}\nCounter is {counter}") ... greeting, counter = greet("Bob", counter) ... print(f"{greeting}\nCounter is {counter}") ... >>> def greet(name, counter): ... return f"Hi, {name}!", counter + 1 ... >>> main() Hi, Alice! Counter is 1 Hi, Bob! Counter is 2

      現在,通過調用 重新分配每個變量后greet(),您可以看到所需的結果!

      將返回值分配給變量是實現與 Python 中按引用傳遞相同結果的最佳方式。您將在有關最佳實踐的部分中了解原因以及一些其他方法。

      創建條件多返回函數

      這是返回多個值的特定用例,其中該函數可以在條件語句中使用,并且具有額外的副作用,例如修改作為參數傳入的外部變量。

      考慮C# 中的標準Int32.TryParse函數,它返回一個布爾值并同時操作對整數參數的引用:

      public static bool TryParse (string s, out int result);

      此函數嘗試string使用out關鍵字將 a轉換為 32 位有符號整數。有兩種可能的結果:

      如果解析成功,則輸出參數將設置為結果整數,函數將返回true。

      如果解析失敗,則輸出參數將設置為0,函數將返回false。

      您可以在以下示例中在實踐中看到這一點,該示例嘗試轉換許多不同的字符串:

      using System; // Source: // https://docs.microsoft.com/en-us/dotnet/api/system.int32.tryparse?view=netcore-3.1#System_Int32_TryParse_System_String_System_Int32__ public class Example { public static void Main() { String[] values = { null, "160519", "9432.0", "16,667", " -322 ", "+4302", "(100);", "01FA" }; foreach (var value in values) { int number; if (Int32.TryParse(value, out number)) { Console.WriteLine("Converted '{0}' to {1}.", value, number); } else { Console.WriteLine("Attempted conversion of '{0}' failed.", value ?? ""); } } } }

      上面的代碼試圖通過 將不同格式的字符串轉換為整數TryParse(),輸出如下:

      Attempted conversion of '' failed. Converted '160519' to 160519. Attempted conversion of '9432.0' failed. Attempted conversion of '16,667' failed. Converted ' -322 ' to -322. Converted '+4302' to 4302. Attempted conversion of '(100);' failed. Attempted conversion of '01FA' failed.

      要在 Python 中實現類似的功能,您可以使用之前看到的多個返回值:

      def tryparse(string, base=10): try: return True, int(string, base=base) except ValueError: return False, None

      這tryparse()將返回兩個值。第一個值指示轉換是否成功,第二個值保存結果(None如果失敗,則為 )。

      但是,使用此函數有點笨拙,因為您需要在每次調用時解壓縮返回值。這意味著您不能在if語句中使用該函數:

      >>>

      >>> success, result = tryparse("123") >>> success True >>> result 123 >>> # We can make the check work >>> # by accessing the first element of the returned tuple, >>> # but there's no way to reassign the second element to `result`: >>> if tryparse("456")[0]: ... print(result) ... 123

      盡管它通常通過返回多個值來工作,tryparse()但不能用于條件檢查。這意味著您還有一些工作要做。

      您可以利用 Python 的靈活性并簡化函數以根據轉換是否成功返回不同類型的單個值:

      def tryparse(string, base=10): try: return int(string, base=base) except ValueError: return None

      由于 Python 函數能夠返回不同的數據類型,您現在可以在條件語句中使用此函數。但是如何?難道您不必先調用函數,分配其返回值,然后檢查值本身嗎?

      通過利用 Python 在對象類型方面的靈活性,以及Python 3.8 中的新賦值表達式,您可以在條件if語句中調用這個簡化的函數,并在檢查通過時獲取返回值:

      >>>

      >>> if (n := tryparse("123")) is not None: ... print(n) ... 123 >>> if (n := tryparse("abc")) is None: ... print(n) ... None >>> # You can even do arithmetic! >>> 10 * tryparse("10") 100 >>> # All the functionality of int() is available: >>> 10 * tryparse("0a", base=16) 100 >>> # You can also embed the check within the arithmetic expression! >>> 10 * (n if (n := tryparse("123")) is not None else 1) 1230 >>> 10 * (n if (n := tryparse("abc")) is not None else 1) 10

      哇!這個 Python 版本tryparse()比 C# 版本更強大,允許您在條件語句和算術表達式中使用它。

      通過一點點獨創性,您已經復制了一個特定且有用的傳遞引用模式,而實際上并沒有通過引用傳遞參數。事實上,在使用賦值表達式 operator(?) 并直接在 Python 表達式中使用返回值時,您又一次賦值了返回值:=。

      到目前為止,您已經了解了按引用傳遞的含義,它與按值傳遞有何不同,以及 Python 的方法與兩者有何不同?,F在您已準備好仔細研究 Python 如何處理函數參數!

      在 Python 中傳遞參數

      Python 通過賦值傳遞參數。也就是說,當你調用一個 Python 函數時,每個函數參數都變成了一個變量,傳遞的值會被賦值給這個變量。

      因此,您可以通過了解賦值機制本身的工作原理,甚至在函數外部,了解有關 Python 如何處理函數參數的重要細節。

      理解 Python 中的賦值

      Python 的賦值語句語言參考提供了以下詳細信息:

      如果賦值目標是標識符或變量名,則此名稱綁定到對象。例如,在x = 2,x是名稱,2是對象。

      如果名稱已經綁定到一個單獨的對象,那么它會重新綁定到新對象。例如,如果x是2并且您發出x = 3,則變量名稱x將重新綁定到3。

      所有Python 對象都以特定結構實現。此結構的屬性之一是一個計數器,用于跟蹤已綁定到此對象的名稱的數量。

      注意:此計數器稱為引用計數器,因為它會跟蹤指向同一對象的引用或名稱的數量。不要將引用計數器與通過引用傳遞的概念混淆,因為兩者無關。

      Python 文檔提供了有關引用計數的更多詳細信息。

      讓我們繼續這個x = 2例子,看看當你給一個新變量賦值時會發生什么:

      如果表示該值的對象2已經存在,則檢索它。否則,它被創建。

      此對象的引用計數器遞增。

      在當前命名空間中添加一個條目以將標識符綁定x到表示 的對象2。該條目實際上是存儲在字典中的鍵值對!該字典的表示由locals()or返回globals()。

      現在,如果您重新分配x給不同的值,會發生以下情況:

      所代表對象的引用計數器2遞減。

      表示新值的對象的引用計數器遞增。

      當前命名空間的字典被更新以與x表示新值的對象相關。

      Python 允許您使用函數獲取任意值的引用計數sys.getrefcount()。您可以用它來說明分配如何增加和減少這些引用計數器。請注意,交互式解釋器采用的行為會產生不同的結果,因此您應該從文件中運行以下代碼:

      from sys import getrefcount print("--- Before assignment ---") print(f"References to value_1: {getrefcount('value_1')}") print(f"References to value_2: {getrefcount('value_2')}") x = "value_1" print("--- After assignment ---") print(f"References to value_1: {getrefcount('value_1')}") print(f"References to value_2: {getrefcount('value_2')}") x = "value_2" print("--- After reassignment ---") print(f"References to value_1: {getrefcount('value_1')}") print(f"References to value_2: {getrefcount('value_2')}")

      此腳本將顯示分配前、分配后和重新分配后每個值的引用計數:

      --- Before assignment --- References to value_1: 3 References to value_2: 3 --- After assignment --- References to value_1: 4 References to value_2: 3 --- After reassignment --- References to value_1: 3 References to value_2: 4

      這些結果說明了標識符(變量名)和代表不同值的 Python 對象之間的關系。當您將多個變量分配給相同的值時,Python 會增加現有對象的引用計數器并更新當前命名空間,而不是在內存中創建重復的對象。

      在下一節中,您將通過探索 Python 如何處理函數參數,以您當前對賦值操作的理解為基礎。

      探索函數參數

      Python 中的函數參數是局部變量。這意味著什么?Local是 Python 的作用域之一。這些范圍由上一節中提到的命名空間字典表示。您可以分別使用locals()和globals()來檢索本地和全局命名空間字典。

      執行時,每個函數都有自己的本地命名空間:

      >>>

      >>> def show_locals(): ... my_local = True ... print(locals()) ... >>> show_locals() {'my_local': True}

      使用locals(),您可以證明函數參數成為函數本地命名空間中的常規變量。讓我們my_arg向函數添加一個參數 ,?:

      >>>

      >>> def show_locals(my_arg): ... my_local = True ... print(locals()) ... >>> show_locals("arg_value") {'my_arg': 'arg_value', 'my_local': True}

      您還可以使用sys.getrefcount()來顯示函數參數如何增加對象的引用計數器:

      >>>

      >>> from sys import getrefcount >>> def show_refcount(my_arg): ... return getrefcount(my_arg) ... >>> getrefcount("my_value") 3 >>> show_refcount("my_value") 5

      上面的腳本首先輸出了"my_value"外部引用計數,然后是內部show_refcount()引用計數,顯示引用計數增加的不是 1,而是 2!

      那是因為,除了show_refcount()它本身之外,對sys.getrefcount()inside的調用show_refcount()也my_arg作為參數接收。這my_arg位于 for 的本地命名空間中sys.getrefcount(),添加了對 的額外引用"my_value"。

      通過檢查函數內部的命名空間和引用計數,您可以看到函數參數的工作方式與賦值完全一樣:Python 在函數的本地命名空間中在標識符和表示參數值的 Python 對象之間創建綁定。這些綁定中的每一個都會增加對象的引用計數器。

      現在你可以看到 Python 如何通過賦值來傳遞參數了!

      使用 Python 復制引用傳遞

      在上一節中檢查了命名空間后,您可能會問為什么global沒有提到作為一種修改變量的方法,就像它們通過引用傳遞一樣:

      >>>

      >>> def square(): ... # Not recommended! ... global n ... n *= n ... >>> n = 4 >>> square() >>> n 16

      使用該global語句通常會影響代碼的清晰度。它可能會產生許多問題,包括:

      自由變量,看似無關

      所述變量沒有顯式參數的函數

      不能與其他變量或參數一起使用的函數,因為它們依賴于單個全局變量

      使用全局變量時缺乏線程安全性

      將前面的示例與以下示例進行對比,該示例顯式返回一個值:

      >>>

      >>> def square(n): ... return n * n ... >>> square(4) 16

      好多了!您避免了全局變量的所有潛在問題,并且通過要求參數,您可以使您的函數更清晰。

      盡管既不是按引用傳遞的語言也不是按值傳遞的語言,Python 在這方面沒有任何缺點。它的靈活性足以應對挑戰。

      最佳實踐:返回和重新分配

      您已經接觸到從函數返回值并將它們重新分配給變量。對于對單個值進行操作的函數,返回值比使用引用要清晰得多。此外,由于 Python 已經在幕后使用了指針,因此即使它能夠通過引用傳遞參數,也不會有額外的性能優勢。

      旨在編寫返回一個值的單一用途函數,然后(重新)將該值分配給變量,如下例所示:

      def square(n): # Accept an argument, return a value. return n * n x = 4 ... # Later, reassign the return value: x = square(x)

      返回和分配值還可以使您的意圖明確并且您的代碼更易于理解和測試。

      對于對多個值進行操作的函數,您已經看到 Python 能夠返回值元組。由于 Python 的靈活性,您甚至超越了C#中Int32.TryParse()的優雅!

      如果您需要對多個值進行操作,那么您可以編寫返回多個值的單一用途函數,然后(重新)將這些值分配給變量。下面是一個例子:

      def greet(name, counter): # Return multiple values return f"Hi, {name}!", counter + 1 counter = 0 ... # Later, reassign each return value by unpacking. greeting, counter = greet("Alice", counter)

      調用返回多個值的函數時,可以同時分配多個變量。

      最佳實踐:使用對象屬性

      對象屬性在 Python 的賦值策略中占有一席之地。Python 的賦值語句語言參考指出,如果目標是支持賦值的對象屬性,則將要求該對象對該屬性執行賦值。如果將對象作為參數傳遞給函數,則可以就地修改其屬性。

      編寫接受具有屬性的對象的函數,然后直接對這些屬性進行操作,如下例所示:

      >>>

      >>> # For the purpose of this example, let's use SimpleNamespace. >>> from types import SimpleNamespace >>> # SimpleNamespace allows us to set arbitrary attributes. >>> # It is an explicit, handy replacement for "class X: pass". >>> ns = SimpleNamespace() >>> # Define a function to operate on an object's attribute. >>> def square(instance): ... instance.n *= instance.n ... >>> ns.n = 4 >>> square(ns) >>> ns.n 16

      注意square()需要寫成直接對一個屬性進行操作,修改后不需要重新賦值返回值。

      值得重申的是,您應該確保該屬性支持賦值!這是與 相同的示例namedtuple,其屬性是只讀的:

      >>>

      >>> from collections import namedtuple >>> NS = namedtuple("NS", "n") >>> def square(instance): ... instance.n *= instance.n ... >>> ns = NS(4) >>> ns.n 4 >>> square(ns) Traceback (most recent call last): File "", line 1, in File "", line 2, in square AttributeError: can't set attribute

      嘗試修改不允許修改的屬性會導致AttributeError.

      此外,您應該注意類屬性。它們將保持不變,并且將創建和修改實例屬性:

      >>>

      >>> class NS: ... n = 4 ... >>> ns = NS() >>> def square(instance): ... instance.n *= instance.n ... >>> ns.n 4 >>> square(ns) >>> # Instance attribute is modified. >>> ns.n 16 >>> # Class attribute remains unchanged. >>> NS.n 4

      由于類屬性在通過類實例修改時保持不變,因此您需要記住引用實例屬性。

      最佳實踐:使用字典和列表

      Python中的字典是與所有其他內置類型不同的對象類型。它們被稱為映射類型。Python 的映射類型文檔提供了對該術語的一些了解:

      甲映射對象映射可哈希值到任意對象。映射是可變對象。目前只有一種標準映射類型,即字典。(來源)

      本教程不涉及如何實現自定義映射類型,但您可以使用簡陋的字典復制通過引用傳遞。這是一個使用直接對字典元素進行操作的函數的示例:

      >>>

      >>> # Dictionaries are mapping types. >>> mt = {"n": 4} >>> # Define a function to operate on a key: >>> def square(num_dict): ... num_dict["n"] *= num_dict["n"] ... >>> square(mt) >>> mt {'n': 16}

      由于您將值重新分配給字典鍵,因此對字典元素進行操作仍然是一種賦值形式。使用字典,您可以獲得通過相同字典對象訪問修改后的值的額外實用性。

      雖然列表不是映射類型,但由于兩個重要特征:下標性和可變性,您可以以類似于字典的方式使用它們。這些特性值得多解釋一下,但讓我們先來看看使用 Python 列表模擬按引用傳遞的最佳實踐。

      要使用列表復制引用傳遞,請編寫一個直接對列表元素進行操作的函數:

      >>>

      >>> # Lists are both subscriptable and mutable. >>> sm = [4] >>> # Define a function to operate on an index: >>> def square(num_list): ... num_list[0] *= num_list[0] ... >>> square(sm) >>> sm [16]

      由于您將值重新分配給列表中的元素,因此對列表元素進行操作仍然是一種賦值形式。與字典類似,列表允許您通過相同的列表對象訪問修改后的值。

      現在讓我們探索可訂閱性。當可以通過索引位置訪問其結構的子集時,對象是可下標的:

      >>>

      >>> subscriptable = [0, 1, 2] # A list >>> subscriptable[0] 0 >>> subscriptable = (0, 1, 2) # A tuple >>> subscriptable[0] 0 >>> subscriptable = "012" # A string >>> subscriptable[0] '0' >>> not_subscriptable = {0, 1, 2} # A set >>> not_subscriptable[0] Traceback (most recent call last): File "", line 1, in TypeError: 'set' object is not subscriptable

      列表、元組和字符串是可下標的,但集合不是。嘗試訪問不可下標的對象元素將引發TypeError.

      可變性是一個更廣泛的主題,需要額外的探索和文檔參考。簡而言之,如果一個對象的結構可以就地更改而不是需要重新分配,則該對象是可變的:

      >>>

      >>> mutable = [0, 1, 2] # A list >>> mutable[0] = "x" >>> mutable ['x', 1, 2] >>> not_mutable = (0, 1, 2) # A tuple >>> not_mutable[0] = "x" Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment >>> not_mutable = "012" # A string >>> not_mutable[0] = "x" Traceback (most recent call last): File "", line 1, in TypeError: 'str' object does not support item assignment >>> mutable = {0, 1, 2} # A set >>> mutable.remove(0) >>> mutable.add("x") >>> mutable {1, 2, 'x'}

      列表和集合是可變的,字典和其他映射類型也是如此。字符串和元組是不可變的。嘗試修改不可變對象的元素將引發TypeError.

      結論

      Python 與支持按引用或按值傳遞參數的語言不同。函數參數成為分配給傳遞給函數的每個值的局部變量。但這并不妨礙您獲得在其他語言中通過引用傳遞參數時所期望的相同結果。

      在本教程中,您學習了:

      Python 如何處理給變量賦值

      Python中如何通過賦值傳遞函數參數

      為什么返回值是復制通過引用傳遞的最佳實踐

      如何使用屬性、字典和列表作為替代最佳實踐

      您還學習了一些在 Python 中復制傳遞引用結構的其他最佳實踐。您可以使用這些知識來實現 傳統上需要支持按引用傳遞的模式。

      為了繼續您的 Python 之旅,我鼓勵您深入研究您在這里遇到的一些相關主題,例如可變性、賦值表達式以及Python 命名空間和作用域。

      保持好奇,我們下期再見!

      Python

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:建筑材料生產專用機械制造(建筑材料生產專用機械制造設備)
      下一篇:銳馳項目管理
      相關文章
      色窝窝亚洲AV网在线观看| 亚洲一级特黄特黄的大片 | 亚洲免费人成视频观看| 亚洲国产国产综合一区首页| 无码久久精品国产亚洲Av影片| 国产自偷亚洲精品页65页| 亚洲国产精品丝袜在线观看| 亚洲av日韩av欧v在线天堂| 狠狠综合亚洲综合亚洲色| 国产精品久久久久久亚洲影视| 亚洲av无码专区国产不乱码| 精品国产亚洲第一区二区三区| 久久亚洲精品无码gv| 国产成人亚洲综合无| 亚洲成a人片在线观看老师| 亚洲国产一区明星换脸| 亚洲免费无码在线| 曰韩亚洲av人人夜夜澡人人爽| 亚洲精品美女久久777777| 亚洲av综合av一区| 亚洲精品在线观看视频| 91久久亚洲国产成人精品性色| 在线观看亚洲人成网站| 亚洲国产av高清无码| 欧洲 亚洲 国产图片综合| 亚洲精品理论电影在线观看| 内射无码专区久久亚洲| 亚洲午夜无码AV毛片久久| 亚洲熟妇无码八AV在线播放| 亚洲AV午夜福利精品一区二区| 亚洲国产精品自在线一区二区| 亚洲色成人网一二三区| 亚洲伦理一二三四| 亚洲乱亚洲乱妇24p| www.91亚洲| 亚洲日本乱码在线观看| 亚洲国产精品自在在线观看| 亚洲天堂电影在线观看| 亚洲国产区男人本色| 亚洲精品综合久久| 亚洲国产精品久久66|