Hướng dẫn python store reference to function - tham chiếu cửa hàng python đến chức năng

Về cơ bản có ba loại 'cuộc gọi chức năng':

Show
  • Vượt qua giá trị
  • Vượt qua tham chiếu
  • Đi qua tham chiếu đối tượng

Python là ngôn ngữ lập trình tham chiếu qua từng đối tượng.

Đầu tiên, điều quan trọng là phải hiểu rằng một biến và giá trị của biến (đối tượng) là hai điều riêng biệt. Biến 'trỏ đến' đối tượng. Biến không phải là đối tượng. Lại:

Biến không phải là đối tượng

Ví dụ: Trong dòng mã sau:

>>> x = []

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
7 là danh sách trống,
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 là một biến chỉ vào danh sách trống, nhưng bản thân
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 không phải là danh sách trống.

Hãy xem xét biến (

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8, trong trường hợp trên) là một hộp và 'giá trị' của biến (
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
7) là đối tượng bên trong hộp.

Vượt qua tham chiếu đối tượng (trường hợp trong Python):

Ở đây, "Tài liệu tham khảo đối tượng được truyền bởi giá trị."

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x

Ở đây, câu lệnh

[0]
2 tạo ra một biến
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 (hộp) hướng về đối tượng
[0]
4.

Trên chức năng được gọi, một hộp mới

[0]
5 được tạo. Nội dung của
[0]
5 giống như nội dung của hộp
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8. Cả hai hộp chứa cùng một đối tượng. Đó là, cả hai biến đều chỉ vào cùng một đối tượng trong bộ nhớ. Do đó, bất kỳ thay đổi nào đối với đối tượng được chỉ ra bởi
[0]
5 cũng sẽ được phản ánh bởi đối tượng được chỉ vào bằng
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8.Both the boxes contain the same object. That is, both the variables point to the same object in memory. Hence, any change to the object pointed at by
[0]
5 will also be reflected by the object pointed at by
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8.

Tóm lại, đầu ra của chương trình trên sẽ là:

[0, 1]

Note:

Nếu biến

[0]
5 được chỉ định lại trong hàm, thì
[0]
5 sẽ trỏ đến một đối tượng riêng trong bộ nhớ.
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 Tuy nhiên, sẽ tiếp tục chỉ vào cùng một đối tượng trong bộ nhớ mà nó đã chỉ vào trước đó.

Example:

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x

Đầu ra của chương trình sẽ là:

[0]

Vượt qua tham chiếu:

Hộp từ hàm gọi được chuyển đến hàm được gọi. Hoàn toàn, nội dung của hộp (giá trị của biến) được truyền vào hàm được gọi. Do đó, bất kỳ thay đổi nào đối với nội dung của hộp trong hàm được gọi sẽ được phản ánh trong hàm gọi.

Vượt qua giá trị:

Một hộp mới được tạo trong hàm được gọi là và các bản sao của nội dung của hộp từ hàm gọi được lưu trữ vào các hộp mới.

Hi vọng điêu nay co ich.

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem cùng với hướng dẫn bằng văn bản để hiểu sâu hơn về sự hiểu biết của bạn: vượt qua tham chiếu trong Python: Thực tiễn tốt nhất This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Pass by Reference in Python: Best Practices

Làm thế nào để bạn lưu trữ tài liệu tham khảo trong Python?references to existing variables, which is known as pass by reference. Other languages handle them as independent values, an approach known as pass by value.

Các giá trị tham chiếu được ẩn trong Python. Không có loại người dùng rõ ràng để lưu trữ giá trị tham chiếu. Tuy nhiên, bạn có thể sử dụng một phần tử danh sách (hoặc phần tử trong bất kỳ loại container phù hợp nào khác) làm biến tham chiếu, bởi vì tất cả các container đều lưu trữ các phần tử cũng là tham chiếu đến các đối tượng đích.

Làm thế nào để bạn tham khảo một chức năng trong Python?

  • Để sử dụng các hàm trong Python, bạn viết tên hàm (hoặc biến trỏ đến đối tượng hàm) theo sau là dấu ngoặc đơn (để gọi hàm). Nếu hàm đó chấp nhận các đối số (như hầu hết các hàm), thì bạn sẽ chuyển các đối số bên trong dấu ngoặc đơn khi bạn gọi hàm.pass by reference and why you’d want to do so
  • Làm thế nào để bạn lưu trữ một chức năng trong một biến trong Python?passing by value and Python’s unique approach
  • Chỉ cần gán một hàm cho biến mong muốn nhưng không có () tức là chỉ với tên của hàm. Nếu biến được gán với hàm cùng với dấu ngoặc (), sẽ không được trả về.function arguments behave in Python
  • Bạn có thể lưu trữ một chức năng trong danh sách Python không?mutable types to pass by reference in Python
  • Các chức năng có thể được lưu trữ dưới dạng các yếu tố của danh sách hoặc bất kỳ cấu trúc dữ liệu nào khác trong Python.best practices are for replicating pass by reference in Python

Sau khi đạt được sự quen thuộc với Python, bạn có thể nhận thấy các trường hợp trong đó các chức năng của bạn không sửa đổi các đối số như bạn có thể mong đợi, đặc biệt là nếu bạn quen thuộc với các ngôn ngữ lập trình khác. Một số ngôn ngữ xử lý các đối số chức năng như các tham chiếu đến các biến hiện có, được gọi là vượt qua bởi tham chiếu. Các ngôn ngữ khác xử lý chúng là giá trị độc lập, một cách tiếp cận được gọi là vượt qua giá trị.

Nếu bạn là một lập trình viên Python trung gian, người muốn hiểu cách xử lý các đối số chức năng đặc biệt của Python, thì hướng dẫn này là dành cho bạn. Bạn sẽ thực hiện các trường hợp sử dụng thực sự của các cấu trúc ngang qua trong Python và tìm hiểu một số thực tiễn tốt nhất để tránh những cạm bẫy với các đối số chức năng của bạn.

  • Trong hướng dẫn này, bạn sẽ học: means to provide an argument to a function.
  • Ý nghĩa của việc vượt qua tham chiếu và lý do tại sao bạn muốn làm như vậy means that the argument you’re passing to the function is a reference to a variable that already exists in memory rather than an independent copy of that variable.

Làm thế nào vượt qua bởi tham chiếu khác với cả hai vượt qua giá trị và cách tiếp cận độc đáo của Python

Cách các đối số chức năng hoạt động trong Python

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;
    }
}

Cách bạn có thể sử dụng một số loại có thể thay đổi để vượt qua tham chiếu trong Python

Thực tiễn tốt nhất là gì để sao chép vượt qua bằng cách tham khảo trong Python

Xác định vượt qua theo tham chiếu

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

Trước khi bạn đi sâu vào các chi tiết kỹ thuật của việc truyền qua tài liệu tham khảo, nó rất hữu ích để xem xét kỹ hơn thuật ngữ này bằng cách chia nó thành các thành phần:

Không hẳn. Python chuyển các đối số không bằng cách tham chiếu cũng như giá trị, mà bằng cách gán. Dưới đây, bạn sẽ nhanh chóng khám phá các chi tiết về việc chuyển bằng giá trị và vượt qua bằng cách tham khảo trước khi xem xét kỹ hơn theo cách tiếp cận của Python. Sau đó, bạn sẽ đi qua một số thực tiễn tốt nhất để đạt được sự tương đương của việc vượt qua bằng cách tham khảo trong Python.by assignment. Below, you’ll quickly explore the details of passing by value and passing by reference before looking more closely at Python’s approach. After that, you’ll walk through some best practices for achieving the equivalent of passing by reference in Python.

Tương phản vượt qua bằng cách tham chiếu và vượt qua giá trị

Khi bạn vượt qua các đối số chức năng bằng tham chiếu, các đối số đó chỉ tham khảo các giá trị hiện có. Ngược lại, khi bạn vượt qua các đối số theo giá trị, những đối số đó trở thành bản sao độc lập của các giá trị ban đầu.

Hãy để xem lại ví dụ C#, lần này mà không cần sử dụng từ khóa

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;
    }
}
3. Điều này sẽ khiến chương trình sử dụng hành vi mặc định chuyển bằng giá trị:

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;
    }
}

Ở đây, bạn có thể thấy rằng

>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
0 không sửa đổi biến ban đầu. Thay vào đó,
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
1 là một bản sao độc lập của biến ban đầu
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;
    }
}
8. Mặc dù điều đó phù hợp với hành vi mà bạn sẽ thấy trong Python, hãy nhớ rằng Python không chính xác vượt qua giá trị. Hãy để chứng minh điều đó.

Python sườn tích hợp

>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
3 trả về một số nguyên đại diện cho địa chỉ bộ nhớ của đối tượng mong muốn. Sử dụng
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
3, bạn có thể xác minh các xác nhận sau:

  1. Các đối số chức năng ban đầu đề cập đến cùng một địa chỉ với các biến ban đầu của chúng.
  2. Việc chỉ định lại đối số trong hàm cung cấp cho nó một địa chỉ mới trong khi biến ban đầu vẫn chưa được sửa đổi.

Trong ví dụ dưới đây, lưu ý rằng địa chỉ của

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 ban đầu khớp với
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 nhưng thay đổi sau khi phân công lại, trong khi địa chỉ của
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 không bao giờ thay đổi:

>>>

>>> 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

Thực tế là các địa chỉ ban đầu của

>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 là như nhau khi bạn gọi
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;
    }
}
0 chứng minh rằng đối số
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 không được truyền bởi giá trị. Mặt khác,
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 sẽ có địa chỉ bộ nhớ riêng biệt.

Trước khi bạn tìm hiểu các chi tiết về cách Python xử lý các đối số, hãy để Lôi xem xét một số trường hợp sử dụng thực tế để đi qua bằng cách tham khảo.

Sử dụng các cấu trúc tham chiếu vượt qua

Vượt qua các biến bằng tham chiếu là một trong một số chiến lược bạn có thể sử dụng để thực hiện các mẫu lập trình nhất định. Mặc dù nó hiếm khi cần thiết, nhưng đi qua tham chiếu có thể là một công cụ hữu ích.

Trong phần này, bạn sẽ xem xét ba trong số các mẫu phổ biến nhất mà đi qua bằng cách tham khảo là một cách tiếp cận thực tế. Sau đó, bạn sẽ xem cách bạn có thể thực hiện từng mẫu này với Python.

Tránh các đối tượng trùng lặp

Như bạn đã thấy, việc chuyển một biến theo giá trị sẽ khiến một bản sao của giá trị đó được tạo và lưu trữ trong bộ nhớ. Trong các ngôn ngữ mặc định để truyền theo giá trị, bạn có thể tìm thấy lợi ích hiệu suất từ ​​việc truyền biến bằng cách tham chiếu thay thế, đặc biệt là khi biến chứa rất nhiều dữ liệu. Điều này sẽ rõ ràng hơn khi mã của bạn đang chạy trên các máy bị hạn chế tài nguyên.

Tuy nhiên, trong Python, đây không bao giờ là vấn đề. Bạn sẽ thấy tại sao trong phần tiếp theo.

Trả về nhiều giá trị

Một trong những ứng dụng phổ biến nhất của việc truyền bằng tham chiếu là tạo một hàm làm thay đổi giá trị của các tham số tham chiếu trong khi trả về một giá trị riêng biệt. Bạn có thể sửa đổi ví dụ C# Pass-By-Reference của mình để minh họa kỹ thuật này:

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;
    }
}

Trong ví dụ trên,

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;
    }
}
4 trả về một chuỗi lời chào và cũng sửa đổi giá trị của
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;
    }
}
5. Bây giờ hãy cố gắng tái tạo điều này càng gần càng tốt trong Python:

>>>

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
0

Thực tế là các địa chỉ ban đầu của

>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 là như nhau khi bạn gọi
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;
    }
}
0 chứng minh rằng đối số
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 không được truyền bởi giá trị. Mặt khác,
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 sẽ có địa chỉ bộ nhớ riêng biệt.

Trước khi bạn tìm hiểu các chi tiết về cách Python xử lý các đối số, hãy để Lôi xem xét một số trường hợp sử dụng thực tế để đi qua bằng cách tham khảo.

Sử dụng các cấu trúc tham chiếu vượt qua

>>>

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
1

Thực tế là các địa chỉ ban đầu của

>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 là như nhau khi bạn gọi
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;
    }
}
0 chứng minh rằng đối số
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 không được truyền bởi giá trị. Mặt khác,
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 sẽ có địa chỉ bộ nhớ riêng biệt.

Trước khi bạn tìm hiểu các chi tiết về cách Python xử lý các đối số, hãy để Lôi xem xét một số trường hợp sử dụng thực tế để đi qua bằng cách tham khảo.

>>>

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
2

Thực tế là các địa chỉ ban đầu của

>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 là như nhau khi bạn gọi
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;
    }
}
0 chứng minh rằng đối số
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 không được truyền bởi giá trị. Mặt khác,
>>> def main():
...     arg = 4
...     square(arg)
...     print(arg)
...
>>> def square(n):
...     n *= n
...
>>> main()
4
6 và
def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 sẽ có địa chỉ bộ nhớ riêng biệt.

Trước khi bạn tìm hiểu các chi tiết về cách Python xử lý các đối số, hãy để Lôi xem xét một số trường hợp sử dụng thực tế để đi qua bằng cách tham khảo.reassign your

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;
    }
}
5 variable with each call to
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;
    }
}
4:

>>>

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
3

Bây giờ, sau khi chỉ định lại từng biến với một cuộc gọi đến

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;
    }
}
4, bạn có thể thấy kết quả mong muốn!

Gán các giá trị trả về cho các biến là cách tốt nhất để đạt được kết quả tương tự như truyền bằng cách tham chiếu trong Python. Bạn sẽ tìm hiểu lý do tại sao, cùng với một số phương pháp bổ sung, trong phần về các thực tiễn tốt nhất.

Tạo các chức năng đa hoàn trả có điều kiện

Đây là một trường hợp sử dụng cụ thể của việc trả về nhiều giá trị trong đó hàm có thể được sử dụng trong một câu lệnh có điều kiện và có các tác dụng phụ bổ sung như sửa đổi một biến bên ngoài được truyền như một đối số.

Hãy xem xét chức năng Int32.TryParse tiêu chuẩn trong C#, trả về Boolean và hoạt động trên một tham chiếu đến một đối số số nguyên cùng một lúc:

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
4

Hàm này cố gắng chuyển đổi

>>> 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
7 thành số nguyên có chữ ký 32 bit bằng cách sử dụng từ khóa
>>> 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
8. Có hai kết quả có thể xảy ra:

  1. Nếu phân tích cú pháp thành công, thì tham số đầu ra sẽ được đặt thành số nguyên kết quả và hàm sẽ trả về
    >>> 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
    
    9.
    , then the output parameter will be set to the resulting integer, and the function will return
    >>> 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
    
    9.
  2. Nếu phân tích cú pháp không thành công, thì tham số đầu ra sẽ được đặt thành
    >>> 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
    
    3 và hàm sẽ trả về
    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;
        }
    }
    
    1.
    , then the output parameter will be set to
    >>> 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
    
    3, and the function will return
    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;
        }
    }
    
    1.

Bạn có thể thấy điều này trong thực tế trong ví dụ sau, cố gắng chuyển đổi một số chuỗi khác nhau:

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
5

Mã trên, cố gắng chuyển đổi các chuỗi được định dạng khác nhau thành số nguyên thông qua

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;
    }
}
2, xuất ra như sau:

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
6

Để thực hiện một chức năng tương tự trong Python, bạn có thể sử dụng nhiều giá trị trả về như bạn đã thấy trước đây:

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
7

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;
    }
}
3 này trả về hai giá trị. Giá trị đầu tiên cho biết việc chuyển đổi có thành công hay không và lần thứ hai giữ kết quả (hoặ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;
    }
}
4, trong trường hợp thất bại).

Tuy nhiên, sử dụng chức năng này là một chút lộn xộn vì bạn cần giải nén các giá trị trả về với mỗi cuộc gọi. Điều này có nghĩa là bạn có thể sử dụng chức năng trong câu lệnh

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;
    }
}
5:

>>>

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
8

Mặc dù nó thường hoạt động bằng cách trả về nhiều giá trị,

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;
    }
}
3 có thể được sử dụng trong kiểm tra điều kiện. Điều đó có nghĩa là bạn có thêm một số việc phải làm.

Bạn có thể tận dụng tính linh hoạt của Python và đơn giản hóa chức năng để trả về một giá trị duy nhất của các loại khác nhau tùy thuộc vào việc chuyển đổi có thành công hay không:

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
9

Với khả năng các chức năng Python trả về các loại dữ liệu khác nhau, giờ đây bạn có thể sử dụng chức năng này trong một câu lệnh có điều kiện. Nhưng bằng cách nào? Bạn sẽ phải gọi hàm trước, gán giá trị trả về của nó và sau đó kiểm tra giá trị?

Bằng cách tận dụng tính linh hoạt của Python, trong các loại đối tượng, cũng như các biểu thức gán mới trong Python 3.8, bạn có thể gọi hàm đơn giản này trong câu lệnh

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;
    }
}
5 có điều kiện và nhận giá trị trả về nếu kiểm tra vượt qua:

>>>

[0, 1]
0

Ồ! Phiên bản Python này của

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;
    }
}
3 thậm chí còn mạnh hơn phiên bản C#, cho phép bạn sử dụng nó trong các câu lệnh có điều kiện và trong các biểu thức số học.

Với một chút khéo léo, bạn đã sao chép một mô hình chuyển qua cụ thể và hữu ích mà không thực sự truyền cho các đối số bằng cách tham khảo. Trên thực tế, bạn lại một lần nữa gán các giá trị trả về khi sử dụng toán tử biểu thức gán (____ 99) và sử dụng giá trị trả về trực tiếp trong các biểu thức python.assigning return values when using the assignment expression operator(

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;
    }
}
9) and using the return value directly in Python expressions.

Cho đến nay, bạn đã học được những gì vượt qua bằng cách tham khảo có nghĩa là, nó khác với việc vượt qua giá trị như thế nào và cách tiếp cận của Python khác với cả hai. Bây giờ bạn đã sẵn sàng để xem xét kỹ hơn về cách Python xử lý các đối số chức năng!

Vượt qua các cuộc tranh luận trong Python

Python chuyển các đối số bằng cách chuyển nhượng. Đó là, khi bạn gọi hàm python, mỗi đối số hàm trở thành một biến mà giá trị truyền được gán.

Do đó, bạn có thể tìm hiểu các chi tiết quan trọng về cách Python xử lý các đối số chức năng bằng cách hiểu cách thức cơ chế gán hoạt động, ngay cả các chức năng bên ngoài.

Hiểu nhiệm vụ trong Python

Tham khảo ngôn ngữ Python cho các câu lệnh gán cung cấp các chi tiết sau:

  • Nếu mục tiêu gán là một định danh hoặc tên biến, thì tên này bị ràng buộc với đối tượng. Ví dụ, trong
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    00,
    def append_one(li):
        li = [0, 1]
    x = [0]
    append_one(x)
    print x
    
    8 là tên và
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    02 là đối tượng.
  • Nếu tên đã bị ràng buộc với một đối tượng riêng biệt, thì nó sẽ liên kết lại với đối tượng mới. Ví dụ: nếu
    def append_one(li):
        li = [0, 1]
    x = [0]
    append_one(x)
    print x
    
    8 đã
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    02 và bạn phát hành
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    05, thì tên biến
    def append_one(li):
        li = [0, 1]
    x = [0]
    append_one(x)
    print x
    
    8 được giới hạn lại thành
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    07.

Tất cả các đối tượng Python được thực hiện trong một cấu trúc cụ thể. Một trong những thuộc tính của cấu trúc này là một bộ đếm theo dõi số lượng tên đã bị ràng buộc với đối tượng này.

Hãy để ví dụ về ví dụ

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
00 và kiểm tra những gì xảy ra khi bạn gán giá trị cho một biến mới:

  1. Nếu một đối tượng đại diện cho giá trị
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    02 đã tồn tại, thì nó đã được truy xuất. Nếu không, nó đã tạo ra.
  2. Bộ đếm tham chiếu của đối tượng này được tăng lên.
  3. Một mục được thêm vào không gian tên hiện tại để liên kết định danh
    def append_one(li):
        li = [0, 1]
    x = [0]
    append_one(x)
    print x
    
    8 với đối tượng đại diện cho
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    02. Mục nhập này trên thực tế là một cặp giá trị khóa được lưu trữ trong một từ điển! Một đại diện của từ điển đó được trả lại bởi
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    12 hoặc
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    13.

Bây giờ ở đây, những gì xảy ra nếu bạn phân công lại

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
8 thành một giá trị khác:

  1. Bộ đếm tham chiếu của đối tượng đại diện cho
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    02 bị giảm.
  2. Bộ đếm tham chiếu của đối tượng đại diện cho giá trị mới được tăng lên.
  3. Từ điển cho không gian tên hiện tại được cập nhật để liên hệ
    def append_one(li):
        li = [0, 1]
    x = [0]
    append_one(x)
    print x
    
    8 với đối tượng đại diện cho giá trị mới.

Python cho phép bạn có được số lượng tham chiếu cho các giá trị tùy ý với hàm

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
17. Bạn có thể sử dụng nó để minh họa cách gán tăng và giảm các bộ đếm tham chiếu này. Lưu ý rằng trình thông dịch tương tác sử dụng hành vi sẽ mang lại kết quả khác nhau, vì vậy bạn nên chạy mã sau từ một tệp:

[0, 1]
1

Tập lệnh này sẽ hiển thị số lượng tham chiếu cho từng giá trị trước khi gán, sau khi gán và sau khi phân công lại:

[0, 1]
2

Những kết quả này minh họa mối quan hệ giữa các định danh (tên biến) và các đối tượng Python đại diện cho các giá trị riêng biệt. Khi bạn gán nhiều biến cho cùng một giá trị, Python sẽ tăng bộ đếm tham chiếu cho đối tượng hiện có và cập nhật không gian tên hiện tại thay vì tạo các đối tượng trùng lặp trong bộ nhớ.

Trong phần tiếp theo, bạn sẽ xây dựng dựa trên sự hiểu biết hiện tại của mình về các hoạt động chuyển nhượng bằng cách khám phá cách Python xử lý các đối số chức năng.

Khám phá các đối số chức năng

Đối số chức năng trong Python là các biến cục bộ. Điều đó nghĩa là gì? Địa phương là một trong những phạm vi Python. Các phạm vi này được thể hiện bằng từ điển không gian tên được đề cập trong phần trước. Bạn có thể sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
12 và
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
13 để truy xuất từ ​​điển không gian tên địa phương và toàn cầu.local variables. What does that mean? Local is one of Python’s scopes. These scopes are represented by the namespace dictionaries mentioned in the previous section. You can use
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
12 and
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
13 to retrieve the local and global namespace dictionaries, respectively.

Sau khi thực hiện, mỗi hàm có không gian tên cục bộ riêng:

>>>

[0, 1]
3

Sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
12, bạn có thể chứng minh rằng các đối số chức năng trở thành các biến thường xuyên trong không gian tên cục bộ của hàm. Hãy để thêm một đối số,
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21, vào chức năng:

>>>

[0, 1]
4

Sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
12, bạn có thể chứng minh rằng các đối số chức năng trở thành các biến thường xuyên trong không gian tên cục bộ của hàm. Hãy để thêm một đối số,
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21, vào chức năng:

>>>

[0, 1]
5

Sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
12, bạn có thể chứng minh rằng các đối số chức năng trở thành các biến thường xuyên trong không gian tên cục bộ của hàm. Hãy để thêm một đối số,
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21, vào chức năng:

Bạn cũng có thể sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
17 để hiển thị cách các đối số chức năng tăng bộ đếm tham chiếu cho một đối tượng:

Các đầu ra tập lệnh trên được tính tham chiếu cho

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
23 đầu tiên bên ngoài, sau đó bên trong
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
24, cho thấy mức tăng số lượng tham chiếu không phải một, mà là hai!

Điều đó bởi vì, ngoài chính

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
24, cuộc gọi đến
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
17 bên trong
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
24 cũng nhận được
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21 như một đối số. Điều này đặt
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21 trong không gian tên địa phương cho
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
17, thêm một tham chiếu bổ sung vào
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
23.

Bằng cách kiểm tra các không gian tên và số lượng tham chiếu bên trong các hàm, bạn có thể thấy rằng các đối số chức năng hoạt động chính xác giống như các bài tập: Python tạo các ràng buộc trong hàm tên tên cục bộ giữa các định danh và đối tượng Python đại diện cho các giá trị đối số. Mỗi ràng buộc này sẽ tăng bộ đếm tham chiếu đối tượng.

Bây giờ bạn có thể thấy Python vượt qua các đối số bằng cách chuyển nhượng!

>>>

[0, 1]
6

Sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
12, bạn có thể chứng minh rằng các đối số chức năng trở thành các biến thường xuyên trong không gian tên cục bộ của hàm. Hãy để thêm một đối số,
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21, vào chức năng:

  • Bạn cũng có thể sử dụng
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    17 để hiển thị cách các đối số chức năng tăng bộ đếm tham chiếu cho một đối tượng:
  • Các đầu ra tập lệnh trên được tính tham chiếu cho
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    23 đầu tiên bên ngoài, sau đó bên trong
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    24, cho thấy mức tăng số lượng tham chiếu không phải một, mà là hai!
  • Điều đó bởi vì, ngoài chính
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    24, cuộc gọi đến
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    17 bên trong
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    24 cũng nhận được
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    21 như một đối số. Điều này đặt
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    21 trong không gian tên địa phương cho
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    17, thêm một tham chiếu bổ sung vào
    def append_one(li):
        li.append(1)
    x = [0]
    append_one(x)
    print x
    
    23.
  • Bằng cách kiểm tra các không gian tên và số lượng tham chiếu bên trong các hàm, bạn có thể thấy rằng các đối số chức năng hoạt động chính xác giống như các bài tập: Python tạo các ràng buộc trong hàm tên tên cục bộ giữa các định danh và đối tượng Python đại diện cho các giá trị đối số. Mỗi ràng buộc này sẽ tăng bộ đếm tham chiếu đối tượng.

Bây giờ bạn có thể thấy Python vượt qua các đối số bằng cách chuyển nhượng!

>>>

[0, 1]
7

Sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
12, bạn có thể chứng minh rằng các đối số chức năng trở thành các biến thường xuyên trong không gian tên cục bộ của hàm. Hãy để thêm một đối số,
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21, vào chức năng:

Bạn cũng có thể sử dụng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
17 để hiển thị cách các đối số chức năng tăng bộ đếm tham chiếu cho một đối tượng:

Các đầu ra tập lệnh trên được tính tham chiếu cho def append_one(li): li.append(1) x = [0] append_one(x) print x 23 đầu tiên bên ngoài, sau đó bên trong def append_one(li): li.append(1) x = [0] append_one(x) print x 24, cho thấy mức tăng số lượng tham chiếu không phải một, mà là hai!

Điều đó bởi vì, ngoài chính

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
24, cuộc gọi đến
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
17 bên trong
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
24 cũng nhận được
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21 như một đối số. Điều này đặt
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
21 trong không gian tên địa phương cho
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
17, thêm một tham chiếu bổ sung vào
def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
23.

Nhằm mục đích viết các hàm đơn mục đích trả về một giá trị, sau đó (Re) gán giá trị đó cho các biến, như trong ví dụ sau:

[0, 1]
8

Trả lại và gán các giá trị cũng làm cho ý định của bạn rõ ràng và mã của bạn dễ hiểu và kiểm tra hơn.

Đối với các chức năng hoạt động trên nhiều giá trị, bạn đã thấy rằng Python có khả năng trả lại một bộ giá trị. Bạn thậm chí đã vượt qua sự thanh lịch của int32.tryparse () trong C# nhờ sự linh hoạt của Python!

Nếu bạn cần vận hành trên nhiều giá trị, thì bạn có thể viết các hàm đơn mục đích trả về nhiều giá trị, sau đó (Re) gán các giá trị đó cho các biến. Đây là một ví dụ:

[0, 1]
9

Khi gọi một hàm trả về nhiều giá trị, bạn có thể gán nhiều biến cùng một lúc.

Thực hành tốt nhất: Sử dụng các thuộc tính đối tượng

Các thuộc tính đối tượng có vị trí riêng của chúng trong chiến lược chuyển nhượng Python. Tham chiếu ngôn ngữ Python sườn cho các câu lệnh gán cho thấy rằng nếu mục tiêu là thuộc tính đối tượng hỗ trợ gán, thì đối tượng sẽ được yêu cầu thực hiện bài tập trên thuộc tính đó. Nếu bạn chuyển đối tượng như một đối số cho một hàm, thì các thuộc tính của nó có thể được sửa đổi tại chỗ.

Viết các chức năng chấp nhận các đối tượng với các thuộc tính, sau đó hoạt động trực tiếp trên các thuộc tính đó, như trong ví dụ sau:

>>>

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
0

Lưu ý rằng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
34 cần được viết để hoạt động trực tiếp trên một thuộc tính, sẽ được sửa đổi mà không cần phải gán lại giá trị trả về.

Nó có giá trị lặp lại rằng bạn nên đảm bảo thuộc tính hỗ trợ chuyển nhượng! Ở đây, ví dụ tương tự với

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
35, có thuộc tính chỉ đọc:

>>>

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
1

Lưu ý rằng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
34 cần được viết để hoạt động trực tiếp trên một thuộc tính, sẽ được sửa đổi mà không cần phải gán lại giá trị trả về.

Nó có giá trị lặp lại rằng bạn nên đảm bảo thuộc tính hỗ trợ chuyển nhượng! Ở đây, ví dụ tương tự với

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
35, có thuộc tính chỉ đọc:

>>>

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
2

Lưu ý rằng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
34 cần được viết để hoạt động trực tiếp trên một thuộc tính, sẽ được sửa đổi mà không cần phải gán lại giá trị trả về.

Nó có giá trị lặp lại rằng bạn nên đảm bảo thuộc tính hỗ trợ chuyển nhượng! Ở đây, ví dụ tương tự với def append_one(li): li.append(1) x = [0] append_one(x) print x 35, có thuộc tính chỉ đọc:

Nỗ lực sửa đổi các thuộc tính mà don lồng cho phép sửa đổi dẫn đến

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
36.mapping types. Python’s documentation on mapping types provides some insight into the term:

Ngoài ra, bạn nên chú ý đến các thuộc tính lớp. Chúng sẽ không thay đổi và một thuộc tính thể hiện sẽ được tạo và sửa đổi:

Vì các thuộc tính lớp vẫn không thay đổi khi được sửa đổi thông qua một thể hiện lớp, bạn sẽ cần nhớ tham chiếu thuộc tính thể hiện.

>>>

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
3

Lưu ý rằng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
34 cần được viết để hoạt động trực tiếp trên một thuộc tính, sẽ được sửa đổi mà không cần phải gán lại giá trị trả về.

Nó có giá trị lặp lại rằng bạn nên đảm bảo thuộc tính hỗ trợ chuyển nhượng! Ở đây, ví dụ tương tự với

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
35, có thuộc tính chỉ đọc:subscriptability and mutability. These characteristics are worthy of a little more explanation, but let’s first take a look at best practices for mimicking pass by reference using Python lists.

Nỗ lực sửa đổi các thuộc tính mà don lồng cho phép sửa đổi dẫn đến

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
36.

>>>

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
4

Lưu ý rằng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
34 cần được viết để hoạt động trực tiếp trên một thuộc tính, sẽ được sửa đổi mà không cần phải gán lại giá trị trả về.

Nó có giá trị lặp lại rằng bạn nên đảm bảo thuộc tính hỗ trợ chuyển nhượng! Ở đây, ví dụ tương tự với

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
35, có thuộc tính chỉ đọc:subscriptable when a subset of its structure can be accessed by index positions:

>>>

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
5

Lưu ý rằng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
34 cần được viết để hoạt động trực tiếp trên một thuộc tính, sẽ được sửa đổi mà không cần phải gán lại giá trị trả về.

Nó có giá trị lặp lại rằng bạn nên đảm bảo thuộc tính hỗ trợ chuyển nhượng! Ở đây, ví dụ tương tự với

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
35, có thuộc tính chỉ đọc:mutable if its structure can be changed in place rather than requiring reassignment:

>>>

def append_one(li):
    li = [0, 1]
x = [0]
append_one(x)
print x
6

Lưu ý rằng

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
34 cần được viết để hoạt động trực tiếp trên một thuộc tính, sẽ được sửa đổi mà không cần phải gán lại giá trị trả về.

Nó có giá trị lặp lại rằng bạn nên đảm bảo thuộc tính hỗ trợ chuyển nhượng! Ở đây, ví dụ tương tự với def append_one(li): li.append(1) x = [0] append_one(x) print x 35, có thuộc tính chỉ đọc:

Nỗ lực sửa đổi các thuộc tính mà don lồng cho phép sửa đổi dẫn đến

def append_one(li):
    li.append(1)
x = [0]
append_one(x)
print x
36.

Trong hướng dẫn này, bạn đã học được:

  • Cách Python xử lý việc gán các giá trị cho các biếnassigning values to variables
  • Cách các đối số chức năng được truyền bằng cách chuyển nhượng trong Pythonpassed by assignment in Python
  • Tại sao các giá trị trả lại là một thực tiễn tốt nhất để sao chép vượt qua bằng cách tham khảoreturning values is a best practice for replicating pass by reference
  • Cách sử dụng các thuộc tính, từ điển và danh sách như các thực tiễn tốt nhất thay thếattributes, dictionaries, and lists as alternative best practices

Bạn cũng đã học được một số thực tiễn tốt nhất bổ sung để sao chép các cấu trúc tham chiếu theo từng tham chiếu trong Python. Bạn có thể sử dụng kiến ​​thức này để thực hiện các mẫu có truyền thống cần hỗ trợ để truyền qua tham chiếu.

Để tiếp tục hành trình Python của bạn, tôi khuyến khích bạn đi sâu hơn vào một số chủ đề liên quan mà bạn đã gặp ở đây, như tính biến đổi, biểu thức chuyển nhượng, và không gian tên và phạm vi Python.

Hãy tò mò, và hẹn gặp lại lần sau!

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem cùng với hướng dẫn bằng văn bản để hiểu sâu hơn về sự hiểu biết của bạn: vượt qua tham chiếu trong Python: Thực tiễn tốt nhất This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Pass by Reference in Python: Best Practices

Làm thế nào để bạn lưu trữ tài liệu tham khảo trong Python?

Các giá trị tham chiếu được ẩn trong Python. Không có loại người dùng rõ ràng để lưu trữ giá trị tham chiếu. Tuy nhiên, bạn có thể sử dụng một phần tử danh sách (hoặc phần tử trong bất kỳ loại container phù hợp nào khác) làm biến tham chiếu, bởi vì tất cả các container đều lưu trữ các phần tử cũng là tham chiếu đến các đối tượng đích.use a list element (or element in any other suitable container type) as the reference variable, because all containers do store the elements also as references to the target objects.

Làm thế nào để bạn tham khảo một chức năng trong Python?

Để sử dụng các hàm trong Python, bạn viết tên hàm (hoặc biến trỏ đến đối tượng hàm) theo sau là dấu ngoặc đơn (để gọi hàm).Nếu hàm đó chấp nhận các đối số (như hầu hết các hàm), thì bạn sẽ chuyển các đối số bên trong dấu ngoặc đơn khi bạn gọi hàm.write the function name (or the variable that points to the function object) followed by parentheses (to call the function). If that function accepts arguments (as most functions do), then you'll pass the arguments inside the parentheses as you call the function.

Làm thế nào để bạn lưu trữ một chức năng trong một biến trong Python?

Chỉ cần gán một hàm cho biến mong muốn nhưng không có () tức là chỉ với tên của hàm.Nếu biến được gán với hàm cùng với dấu ngoặc (), sẽ không được trả về.assign a function to the desired variable but without () i.e. just with the name of the function. If the variable is assigned with function along with the brackets (), None will be returned.

Bạn có thể lưu trữ một chức năng trong danh sách Python không?

Các chức năng có thể được lưu trữ dưới dạng các yếu tố của danh sách hoặc bất kỳ cấu trúc dữ liệu nào khác trong Python..