Làm cách nào để bạn sử dụng kết quả của một hàm từ một hàm khác trong python?

Trong bài viết này, chúng ta sẽ thảo luận về cách sử dụng một biến từ một hàm khác trong Python. Nói chung, các chức năng giới hạn phạm vi của các biến trong khối chức năng và chúng không thể được truy cập từ bên ngoài chức năng

Hàm trong Python

Hàm được coi là đối tượng trong Python. Điều đó có nghĩa là chúng có thể được truyền dưới dạng đối số, được gán và lưu trữ trong các biến. Cũng có thể liên kết biến với hàm trong Python. Đây là cách chúng ta sẽ tiếp cận nhiệm vụ hiện tại là truy cập một biến từ bên ngoài hàm. Điều này được thực hiện tương tự như cách chúng ta truy cập các thành viên của một lớp theo đối tượng của chúng bằng cách sử dụng “. " nhà điều hành

Cách sử dụng một biến từ một hàm khác trong Python

Biến có thể được gán cho đối tượng hàm bên trong thân hàm. Vì vậy, biến chỉ tồn tại sau khi hàm được gọi. Khi hàm đã được gọi, biến sẽ được liên kết với đối tượng hàm. Biến này hiện có thể được sử dụng ở bất kỳ đâu bên trong hoặc bên ngoài bất kỳ chức năng nào. Hãy xem một triển khai mẫu tương tự trong đoạn mã dưới đây

def function_1():
    # assigning a string as a member of the function object
    function_1.var = "variable inside function_1"
    print("function_1 has been called")

def function_2():
    print("function_2 has been called")
    print(function_1.var)

function_1()
function_2()

Lưu ý rằng hàm_1 phải được gọi trước, nếu không hàm_2 sẽ truy cập vào một biến chưa được tạo. Chạy cùng mã mà không có hàm_1() sẽ dẫn đến lỗi thuộc tính. Đầu ra cho đoạn mã trên như sau

function_1 has been called
function_2 has been called
variable inside function_1

Đầu ra giải thích rõ ràng luồng điều khiển bên trong mã. Hàm_2 truy cập thuộc tính của hàm_1 phải được gọi trước. Do đó, tôi hy vọng bạn thấy bài viết này hữu ích trong việc hiểu cách truy cập các biến từ một hàm khác trong Python

Xem thêm

  • Lớp và đối tượng trong Python

9 phản hồi cho “Cách sử dụng biến từ hàm khác trong Python”

  1. Rahul tripathi nói.

    Ahhh,,,,cuối cùng tôi cũng có giải pháp mà tôi đang loay hoay trong một giờ qua.
    các trang web như thế này làm cho việc viết mã trở nên thú vị.
    rất nhiều tình yêu dành cho trang web và những lời chúc tốt đẹp nhất.

  2. Rajesh Kumar nói.

    Cảm ơn. Viết rất hay và gọn gàng. Các blog/bài báo khác hơi khó hiểu và gây hiểu nhầm. Điều này là đơn giản và lên đến nhãn hiệu

  3. Evelyn Lau nói.

    Xin chào, nếu tôi có hai biến trong hàm đầu tiên và chỉ muốn sử dụng các biến thứ hai trong hàm thứ hai thì sao?

    • Rajeev D nói.

      Mã này hoạt động vì tên của hàm chính là tên của biến. Nếu bạn có một biến thứ hai trong cùng một hàm, rõ ràng tên sẽ cần phải khác. Trong trường hợp đó, bạn sẽ cần khai báo nó là toàn cầu. Chỉ khi đó nó mới có thể truy cập được vào các chức năng khác

  4. Cá ngừ nói.

    Tôi đang thực hiện đánh giá OOP ngay bây giờ và điều này đã giúp giải quyết vấn đề số 1 của tôi. Cảm ơn bạn rất nhiều, và nó cũng có ý nghĩa. 😀

    ** Bỏ qua tên của tôi btw **

  5. TallGibbs nói.

    Tôi không hiểu chức năng_1. var có thể được nhìn thấy bởi function_2()

    Sự hiểu biết của tôi là chức năng đó_1. var là một biến cục bộ và chỉ được định nghĩa trong phạm vi của hàm đó. Làm cách nào mà hàm_2 có thể “thấy” biến này để in nó?

  6. shabeer youzef nói.

    tôi cũng đang nghĩ về cái đó. Tôi đang làm việc với một chương trình nhỏ như vậy, nếu có ai nhận được câu trả lời thì liên hệ với tôi…

    Một số trình gỡ lỗi cho Python được mô tả bên dưới và chức năng tích hợp sẵn cho phép bạn truy cập vào bất kỳ trình gỡ lỗi nào trong số chúng

    Mô-đun pdb là trình gỡ lỗi chế độ bảng điều khiển đơn giản nhưng đầy đủ cho Python. Nó là một phần của thư viện Python tiêu chuẩn, và là. Bạn cũng có thể viết trình gỡ lỗi của riêng mình bằng cách sử dụng mã cho pdb làm ví dụ

    Môi trường phát triển tương tác IDLE, là một phần của bản phân phối Python tiêu chuẩn (thường có sẵn dưới dạng Công cụ/tập lệnh/idle3), bao gồm trình gỡ lỗi đồ họa

    PythonWin là một IDE Python bao gồm trình gỡ lỗi GUI dựa trên pdb. Trình gỡ lỗi PythonWin tô màu các điểm dừng và có khá nhiều tính năng thú vị như gỡ lỗi các chương trình không phải PythonWin. PythonWin có sẵn như là một phần của dự án pywin32 và là một phần của bản phân phối ActivePython

    Eric là một IDE được xây dựng trên PyQt và thành phần chỉnh sửa Scintilla

    trepan3k là trình gỡ lỗi giống như gdb

    Visual Studio Code là một IDE với các công cụ sửa lỗi tích hợp với phần mềm kiểm soát phiên bản

    Có một số IDE Python thương mại bao gồm trình gỡ lỗi đồ họa. Chúng bao gồm

    • cánh IDE

    • IDE Komodo

    • PyCharm

    Đúng

    Pylint và Pyflakes thực hiện kiểm tra cơ bản sẽ giúp bạn bắt lỗi sớm hơn

    Trình kiểm tra kiểu tĩnh như Mypy, Pyre và Pytype có thể kiểm tra gợi ý kiểu trong mã nguồn Python

    Bạn không cần khả năng biên dịch mã Python thành mã C nếu tất cả những gì bạn muốn là một chương trình độc lập mà người dùng có thể tải xuống và chạy mà không cần phải cài đặt bản phân phối Python trước. Có một số công cụ xác định tập hợp các mô-đun mà chương trình yêu cầu và liên kết các mô-đun này với nhau bằng mã nhị phân Python để tạo ra một tệp thực thi duy nhất

    Một là sử dụng công cụ đóng băng, được bao gồm trong cây nguồn Python dưới dạng Tools/freeze. Nó chuyển đổi mã byte Python thành mảng C;

    Nó hoạt động bằng cách quét đệ quy nguồn của bạn để tìm các câu lệnh nhập (ở cả hai dạng) và tìm kiếm các mô-đun trong đường dẫn Python chuẩn cũng như trong thư mục nguồn (đối với các mô-đun tích hợp). Sau đó, nó biến mã byte cho các mô-đun được viết bằng Python thành mã C (bộ khởi tạo mảng có thể được biến thành các đối tượng mã bằng cách sử dụng mô-đun marshal) và tạo một tệp cấu hình tùy chỉnh chỉ chứa các mô-đun dựng sẵn đó thực sự được sử dụng trong . Sau đó, nó biên dịch mã C được tạo và liên kết nó với phần còn lại của trình thông dịch Python để tạo thành một tệp nhị phân độc lập hoạt động chính xác như tập lệnh của bạn

    Các gói sau đây có thể giúp tạo các tệp thực thi giao diện điều khiển và GUI

    • Nuitka (Đa nền tảng)

    • PyInstaller (Đa nền tảng)

    • PyOxidizer (Đa nền tảng)

    • cx_Freeze (Đa nền tảng)

    • py2app (chỉ dành cho macOS)

    • py2exe (chỉ dành cho Windows)

    Đúng. Kiểu mã hóa cần thiết cho các mô-đun thư viện tiêu chuẩn được ghi lại là PEP 8

    Có thể ngạc nhiên khi nhận được mã đang hoạt động trước đó khi nó được sửa đổi bằng cách thêm câu lệnh gán vào đâu đó trong phần thân của hàm

    mã này

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    

    hoạt động, nhưng mã này

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    

    kết quả là một

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    22

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    

    Điều này là do khi bạn gán một biến trong một phạm vi, biến đó sẽ trở thành cục bộ của phạm vi đó và che khuất bất kỳ biến có tên tương tự nào trong phạm vi bên ngoài. Vì câu lệnh cuối cùng trong foo gán một giá trị mới cho

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24, nên trình biên dịch nhận ra nó là một biến cục bộ. Do đó, khi
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    25 trước đó cố gắng in biến cục bộ chưa được khởi tạo và xảy ra lỗi

    Trong ví dụ trên, bạn có thể truy cập biến phạm vi bên ngoài bằng cách khai báo nó là toàn cầu

    ________số 8

    Khai báo rõ ràng này là cần thiết để nhắc nhở bạn rằng (không giống như tình huống tương tự bề ngoài với các biến lớp và đối tượng), bạn thực sự đang sửa đổi giá trị của biến trong phạm vi bên ngoài

    >>> print(x)
    11
    

    Bạn có thể làm điều tương tự trong phạm vi lồng nhau bằng cách sử dụng từ khóa

    function_1 has been called
    function_2 has been called
    variable inside function_1
    0

    Trong Python, các biến chỉ được tham chiếu bên trong một hàm là toàn cục. Nếu một biến được gán một giá trị ở bất kỳ đâu trong phần thân của hàm, thì biến đó được coi là biến cục bộ trừ khi được khai báo rõ ràng là biến toàn cục

    Mặc dù hơi ngạc nhiên lúc đầu, nhưng một khoảnh khắc cân nhắc sẽ giải thích điều này. Một mặt, việc yêu cầu các biến được chỉ định cung cấp một rào cản chống lại các tác dụng phụ ngoài ý muốn. Mặt khác, nếu

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    27 được yêu cầu cho tất cả các tham chiếu toàn cầu, thì bạn sẽ luôn sử dụng
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    27. Bạn phải khai báo là toàn cầu mọi tham chiếu đến hàm tích hợp hoặc thành phần của mô-đun đã nhập. Sự lộn xộn này sẽ đánh bại tính hữu ích của khai báo
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    27 để xác định các tác dụng phụ

    Giả sử bạn sử dụng vòng lặp for để định nghĩa một số lambda khác nhau (hoặc thậm chí là các hàm đơn giản), e. g

    function_1 has been called
    function_2 has been called
    variable inside function_1
    4

    Điều này cung cấp cho bạn một danh sách chứa 5 lambda tính toán

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    31. Bạn có thể mong đợi rằng, khi được gọi, chúng sẽ quay lại lần lượt là,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    32,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    33,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    34,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    35 và
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    36. Tuy nhiên, khi bạn thực sự thử, bạn sẽ thấy rằng tất cả chúng đều trả về
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    36

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    2

    Điều này xảy ra bởi vì

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 không phải là cục bộ của lambdas, nhưng được xác định ở phạm vi bên ngoài và nó được truy cập khi lambda được gọi — không phải khi nó được xác định. Ở cuối vòng lặp, giá trị của
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 là
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    34, vì vậy tất cả các hàm bây giờ trả về
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    41, i. e.
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    36. Bạn cũng có thể xác minh điều này bằng cách thay đổi giá trị của
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 và xem kết quả của lambdas thay đổi như thế nào

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    9

    Để tránh điều này, bạn cần lưu các giá trị trong các biến cục bộ vào lambdas, để chúng không dựa vào giá trị của biến toàn cầu

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    1

    Ở đây,

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    45 tạo một biến mới
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    46 cục bộ cho lambda và được tính toán khi lambda được xác định sao cho nó có cùng giá trị mà
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 có tại thời điểm đó trong vòng lặp. Điều này có nghĩa là giá trị của
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    46 sẽ là
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    32 trong lambda đầu tiên,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    33 trong lambda thứ hai,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    51 trong lambda thứ ba, v.v. Do đó, mỗi lambda sẽ trả về kết quả chính xác

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    0

    Lưu ý rằng hành vi này không đặc biệt đối với lambdas, nhưng cũng áp dụng cho các chức năng thông thường

    Cách thông thường để chia sẻ thông tin giữa các mô-đun trong một chương trình là tạo một mô-đun đặc biệt (thường được gọi là config hoặc cfg). Chỉ cần nhập mô-đun cấu hình trong tất cả các mô-đun của ứng dụng của bạn; . Bởi vì chỉ có một phiên bản của mỗi mô-đun, mọi thay đổi được thực hiện đối với đối tượng mô-đun sẽ được phản ánh ở mọi nơi. Ví dụ

    cấu hình. py

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    1

    chế độ. py

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    2

    chủ yếu. py

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    3

    Lưu ý rằng việc sử dụng một mô-đun cũng là cơ sở để triển khai mẫu thiết kế đơn lẻ, vì lý do tương tự

    Nói chung, không sử dụng

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    52. Làm như vậy sẽ làm lộn xộn không gian tên của trình nhập và khiến những kẻ lừa đảo khó phát hiện ra các tên không xác định hơn nhiều

    Nhập các mô-đun ở đầu tệp. Làm như vậy sẽ làm rõ những mô-đun khác mà mã của bạn yêu cầu và tránh các câu hỏi liệu tên mô-đun có nằm trong phạm vi hay không. Sử dụng một lần nhập trên mỗi dòng giúp dễ dàng thêm và xóa các lần nhập mô-đun, nhưng sử dụng nhiều lần nhập trên mỗi dòng sẽ sử dụng ít không gian màn hình hơn

    Đó là cách thực hành tốt nếu bạn nhập các mô-đun theo thứ tự sau

    1. mô-đun thư viện tiêu chuẩn – e. g. , , ,

    2. mô-đun thư viện của bên thứ ba (bất kỳ thứ gì được cài đặt trong thư mục gói trang web của Python) – e. g.

      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      57,
      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      58,
      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      59

    3. các mô-đun được phát triển tại địa phương

    Đôi khi cần phải di chuyển quá trình nhập vào một hàm hoặc lớp để tránh các sự cố với quá trình nhập tuần hoàn. Gordon McMillan nói

    Circular imports are fine where both modules use the “import ” form of import. They fail when the 2nd module wants to grab a name out of the first (“from module import name”) and the import is at the top level. That’s because names in the 1st are not yet available, because the first module is busy importing the 2nd.

    Trong trường hợp này, nếu mô-đun thứ hai chỉ được sử dụng trong một chức năng, thì quá trình nhập có thể dễ dàng được chuyển sang chức năng đó. Vào thời điểm quá trình nhập được gọi, mô-đun đầu tiên sẽ khởi tạo xong và mô-đun thứ hai có thể thực hiện quá trình nhập của nó

    Cũng có thể cần phải di chuyển các mục nhập ra khỏi cấp mã cao nhất nếu một số mô-đun dành riêng cho nền tảng. Trong trường hợp đó, thậm chí có thể không nhập được tất cả các mô-đun ở đầu tệp. Trong trường hợp này, nhập đúng mô-đun trong mã dành riêng cho nền tảng tương ứng là một lựa chọn tốt

    Chỉ di chuyển quá trình nhập vào phạm vi cục bộ, chẳng hạn như bên trong định nghĩa hàm, nếu cần giải quyết vấn đề như tránh nhập vòng tròn hoặc đang cố gắng giảm thời gian khởi tạo mô-đun. Kỹ thuật này đặc biệt hữu ích nếu nhiều lần nhập là không cần thiết tùy thuộc vào cách chương trình thực thi. Bạn cũng có thể muốn chuyển các mục nhập vào một chức năng nếu các mô-đun chỉ được sử dụng trong chức năng đó. Lưu ý rằng việc tải mô-đun lần đầu tiên có thể tốn kém do khởi tạo mô-đun một lần, nhưng tải mô-đun nhiều lần hầu như miễn phí, chỉ tốn một vài lần tra cứu từ điển. Ngay cả khi tên mô-đun nằm ngoài phạm vi, thì mô-đun đó vẫn có sẵn trong

    Loại lỗi này thường cắn các lập trình viên mới vào nghề. Hãy xem xét chức năng này

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    4

    Lần đầu tiên bạn gọi chức năng này,

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    61 chứa một mục duy nhất. Lần thứ hai,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    61 chứa hai mục vì khi
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    63 bắt đầu thực thi,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    61 bắt đầu với một mục đã có trong đó

    Người ta thường mong đợi rằng một lệnh gọi hàm sẽ tạo các đối tượng mới cho các giá trị mặc định. Đây không phải là những gì xảy ra. Giá trị mặc định được tạo chính xác một lần, khi chức năng được xác định. Nếu đối tượng đó bị thay đổi, giống như từ điển trong ví dụ này, các lần gọi hàm tiếp theo sẽ tham chiếu đến đối tượng đã thay đổi này

    Theo định nghĩa, các đối tượng bất biến như số, chuỗi, bộ dữ liệu và

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65 sẽ an toàn trước sự thay đổi. Các thay đổi đối với các đối tượng có thể thay đổi như từ điển, danh sách và thể hiện của lớp có thể dẫn đến nhầm lẫn

    Do tính năng này, nên thực hành lập trình tốt là không sử dụng các đối tượng có thể thay đổi làm giá trị mặc định. Thay vào đó, hãy sử dụng

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65 làm giá trị mặc định và bên trong hàm, kiểm tra xem tham số có phải là
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65 hay không và tạo một danh sách/từ điển mới/bất cứ thứ gì nếu đó là. Ví dụ, không viết

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    5

    nhưng

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    6

    Tính năng này có thể hữu ích. Khi bạn có một hàm tốn nhiều thời gian để tính toán, một kỹ thuật phổ biến là lưu vào bộ nhớ đệm các tham số và giá trị kết quả của mỗi lệnh gọi hàm, đồng thời trả về giá trị đã lưu trong bộ nhớ cache nếu giá trị tương tự được yêu cầu lại. Điều này được gọi là "ghi nhớ", và có thể được thực hiện như thế này

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    7

    Bạn có thể sử dụng biến toàn cục chứa từ điển thay vì giá trị mặc định;

    Thu thập các đối số bằng cách sử dụng các chỉ định

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    68 và
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    69 trong danh sách tham số của hàm; . Sau đó, bạn có thể chuyển các đối số này khi gọi một hàm khác bằng cách sử dụng
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    68 và
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    69

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    8

    được xác định bởi các tên xuất hiện trong định nghĩa hàm, trong khi các giá trị thực sự được truyền cho một hàm khi gọi nó. Các tham số xác định những gì một chức năng có thể chấp nhận. Ví dụ, đưa ra định nghĩa hàm

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    9

    foo, bar và kwargs là các tham số của

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    72. Tuy nhiên, khi gọi
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    72 chẳng hạn

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    0

    các giá trị

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    74,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    75 và
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    76 là các đối số

    Nếu bạn đã viết mã như

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    1

    bạn có thể thắc mắc tại sao việc thêm một phần tử vào

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    77 cũng thay đổi cả
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24

    Có hai yếu tố tạo ra kết quả này

    1. Các biến chỉ đơn giản là tên tham chiếu đến các đối tượng. Thực hiện

      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      79 không tạo ra một bản sao của danh sách – nó tạo ra một biến mới
      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      77 đề cập đến cùng một đối tượng mà
      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      24 đề cập đến. Điều này có nghĩa là chỉ có một đối tượng (danh sách) và cả
      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      24 và
      >>> x = 10
      >>> def foo():
      ..     print(x)
      ..     x += 1
      
      77 đều đề cập đến nó

    2. Danh sách là , có nghĩa là bạn có thể thay đổi nội dung của chúng

    Sau khi gọi đến

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    84, nội dung của đối tượng có thể thay đổi đã thay đổi từ
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    85 thành
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    86. Vì cả hai biến đều đề cập đến cùng một đối tượng, sử dụng một trong hai tên sẽ truy cập giá trị đã sửa đổi
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    86

    Thay vào đó, nếu chúng ta gán một đối tượng bất biến cho

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    2

    chúng ta có thể thấy rằng trong trường hợp này,

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 và
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    77 không còn bằng nhau nữa. Điều này là do các số nguyên là , và khi chúng ta thực hiện
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    91, chúng ta sẽ không biến đổi int
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    92 bằng cách tăng giá trị của nó; . Sau phép gán này, chúng ta có hai đối tượng (ints
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    93 và
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    92) và hai biến tham chiếu đến chúng (
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 bây giờ tham chiếu đến
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    93 nhưng
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    77 vẫn tham chiếu đến
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    92)

    Một số thao tác (ví dụ:

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    02 và
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    03) làm thay đổi đối tượng, trong khi các thao tác bề ngoài tương tự (ví dụ:
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    04 và ) tạo ra một đối tượng mới. Nói chung trong Python (và trong mọi trường hợp trong thư viện chuẩn), một phương thức thay đổi một đối tượng sẽ trả về
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65 để giúp tránh nhầm lẫn hai loại hoạt động. Vì vậy, nếu bạn viết nhầm
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    03 và nghĩ rằng nó sẽ cung cấp cho bạn một bản sao được sắp xếp của
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    77, thay vào đó, bạn sẽ kết thúc bằng
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65, điều này có thể khiến chương trình của bạn tạo ra một lỗi dễ chẩn đoán

    Tuy nhiên, có một loại hoạt động trong đó cùng một hoạt động đôi khi có các hành vi khác nhau với các loại khác nhau. toán tử gán tăng cường. Ví dụ:

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    10 thay đổi danh sách nhưng không thay đổi bộ dữ liệu hoặc int (
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    11 tương đương với
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    12 và thay đổi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    13, trong khi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    14 và
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    15 tạo đối tượng mới)

    Nói cách khác

    • Nếu chúng ta có một đối tượng có thể thay đổi (, , v.v. ), chúng ta có thể sử dụng một số thao tác cụ thể để thay đổi nó và tất cả các biến tham chiếu đến nó sẽ thấy sự thay đổi

    • Nếu chúng ta có một đối tượng bất biến (, , , v.v. ), tất cả các biến tham chiếu đến nó sẽ luôn nhìn thấy cùng một giá trị, nhưng các hoạt động chuyển đổi giá trị đó thành một giá trị mới luôn trả về một đối tượng mới

    Nếu bạn muốn biết hai biến có tham chiếu đến cùng một đối tượng hay không, bạn có thể sử dụng toán tử hoặc hàm có sẵn

    Hãy nhớ rằng các đối số được truyền bằng phép gán trong Python. Vì phép gán chỉ tạo các tham chiếu đến các đối tượng, nên không có bí danh giữa tên đối số trong trình gọi và callee, và do đó không có tham chiếu theo từng cuộc gọi. Bạn có thể đạt được hiệu quả mong muốn theo một số cách

    1. Bằng cách trả về một bộ kết quả

      >>> foo()
      Traceback (most recent call last):
        ...
      UnboundLocalError: local variable 'x' referenced before assignment
      
      3

      Đây hầu như luôn là giải pháp rõ ràng nhất

    2. Bằng cách sử dụng các biến toàn cục. Đây không phải là chủ đề an toàn và không được khuyến khích

    3. Bằng cách chuyển một đối tượng có thể thay đổi (có thể thay đổi tại chỗ)

      >>> foo()
      Traceback (most recent call last):
        ...
      UnboundLocalError: local variable 'x' referenced before assignment
      
      4

    4. Bằng cách chuyển vào một từ điển bị biến đổi

      >>> foo()
      Traceback (most recent call last):
        ...
      UnboundLocalError: local variable 'x' referenced before assignment
      
      5

    5. Hoặc gói các giá trị trong một thể hiện của lớp

      >>> foo()
      Traceback (most recent call last):
        ...
      UnboundLocalError: local variable 'x' referenced before assignment
      
      6

      Hầu như không bao giờ có một lý do chính đáng để làm cho điều này trở nên phức tạp

    Lựa chọn tốt nhất của bạn là trả về một bộ chứa nhiều kết quả

    Bạn có hai sự lựa chọn. bạn có thể sử dụng phạm vi lồng nhau hoặc bạn có thể sử dụng các đối tượng có thể gọi được. Ví dụ: giả sử bạn muốn xác định

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    24 trả về hàm
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    25 tính toán giá trị
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    26. Sử dụng phạm vi lồng nhau

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    7

    Hoặc sử dụng một đối tượng có thể gọi được

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    8

    Trong cả hai trường hợp,

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    9

    đưa ra một đối tượng có thể gọi được trong đó

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    27

    Cách tiếp cận đối tượng có thể gọi được có nhược điểm là chậm hơn một chút và dẫn đến mã dài hơn một chút. Tuy nhiên, lưu ý rằng một tập hợp các callable có thể chia sẻ chữ ký của chúng thông qua kế thừa

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    0

    Đối tượng có thể đóng gói trạng thái cho một số phương thức

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    1

    Ở đây

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    28,
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    29 và
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    30 hoạt động giống như các hàm chia sẻ cùng một biến đếm

    Nói chung, hãy thử hoặc cho trường hợp chung. Không phải tất cả các đối tượng có thể được sao chép, nhưng hầu hết có thể

    Một số đối tượng có thể được sao chép dễ dàng hơn. Từ điển có một phương pháp

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    2

    Trình tự có thể được sao chép bằng cách cắt

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    3

    Đối với một thể hiện

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 của một lớp do người dùng định nghĩa, trả về một danh sách được sắp xếp theo thứ tự bảng chữ cái gồm các tên chứa các thuộc tính và phương thức của thể hiện cũng như các thuộc tính được xác định bởi lớp của nó

    Nói chung là không thể, bởi vì các đối tượng không thực sự có tên. Về cơ bản, phép gán luôn gắn tên với giá trị; . Hãy xem xét đoạn mã sau

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    4

    Có thể cho rằng lớp có một tên. mặc dù nó được liên kết với hai tên và được gọi thông qua tên

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    38, thể hiện đã tạo vẫn được báo cáo là một thể hiện của lớp
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    39. Tuy nhiên, không thể nói tên của đối tượng là
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    40 hay
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    41, vì cả hai tên đều bị ràng buộc với cùng một giá trị

    Nói chung, mã của bạn không cần thiết phải “biết tên” của các giá trị cụ thể. Trừ khi bạn đang cố tình viết các chương trình hướng nội, đây thường là dấu hiệu cho thấy việc thay đổi cách tiếp cận có thể có lợi

    trong comp. lang thang. trăn, Fredrik Lundh đã từng đưa ra một phép loại suy tuyệt vời để trả lời cho câu hỏi này

    Giống như cách bạn lấy tên của con mèo mà bạn tìm thấy trên hiên nhà của mình. bản thân con mèo (đối tượng) không thể cho bạn biết tên của nó và nó cũng không thực sự quan tâm – vì vậy cách duy nhất để biết nó được gọi là gì là hỏi tất cả những người hàng xóm (không gian tên) của bạn xem đó có phải là con mèo (đối tượng) của họ không…

    …. và đừng ngạc nhiên nếu bạn thấy rằng nó được biết đến với nhiều tên hoặc không có tên nào cả

    Dấu phẩy không phải là toán tử trong Python. Hãy xem xét phiên này

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    5

    Vì dấu phẩy không phải là toán tử, mà là dấu phân cách giữa các biểu thức, phần trên được đánh giá như thể bạn đã nhập

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    6

    không phải

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    7

    Điều này cũng đúng với các toán tử gán khác nhau (______542,

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    10, v.v.). Chúng không thực sự là toán tử mà là dấu phân cách cú pháp trong câu lệnh gán

    Có, có. Cú pháp như sau

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    8

    Trước khi cú pháp này được giới thiệu trong Python 2. 5, một thành ngữ phổ biến là sử dụng các toán tử logic

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    9

    Tuy nhiên, thành ngữ này không an toàn vì nó có thể cho kết quả sai khi on_true có giá trị boolean sai. Do đó, tốt hơn hết là sử dụng biểu mẫu

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    44

    Đúng. Thông thường, điều này được thực hiện bằng cách lồng vào nhau trong

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    45. Xem ba ví dụ sau, được điều chỉnh một chút từ Ulf Bartelt

    >>> print(x)
    11
    
    0

    Đừng thử điều này ở nhà, trẻ em

    Dấu gạch chéo trong danh sách đối số của hàm biểu thị rằng các tham số trước nó chỉ là vị trí. Tham số chỉ vị trí là những tham số không có tên có thể sử dụng bên ngoài. Khi gọi một hàm chỉ chấp nhận các tham số chỉ vị trí, các đối số được ánh xạ tới các tham số chỉ dựa trên vị trí của chúng. Ví dụ: là một hàm chấp nhận các tham số chỉ vị trí. tài liệu của nó trông như thế này

    >>> print(x)
    11
    
    1

    Dấu gạch chéo ở cuối danh sách tham số có nghĩa là cả hai tham số đều chỉ có vị trí. Do đó, việc gọi với đối số từ khóa sẽ dẫn đến lỗi

    >>> print(x)
    11
    
    2

    Để chỉ định một chữ số bát phân, hãy đặt trước giá trị bát phân bằng số 0, sau đó là chữ "o" viết thường hoặc viết hoa. Ví dụ: để đặt biến “a” thành giá trị bát phân “10” (8 ở dạng thập phân), hãy nhập

    >>> print(x)
    11
    
    3

    Hệ thập lục phân thật dễ dàng. Chỉ cần đặt trước số thập lục phân bằng số 0, sau đó là chữ "x" viết thường hoặc viết hoa. Các chữ số thập lục phân có thể được chỉ định bằng chữ thường hoặc chữ hoa. Ví dụ, trong trình thông dịch Python

    >>> print(x)
    11
    
    4

    Nó chủ yếu được thúc đẩy bởi mong muốn rằng

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    49 có cùng dấu hiệu với
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    50. Nếu bạn muốn điều đó, và cũng muốn

    >>> print(x)
    11
    
    5

    sau đó phép chia số nguyên phải trả về sàn. C cũng yêu cầu giữ danh tính đó, và sau đó các trình biên dịch cắt bớt

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    51 cần làm cho
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    49 có cùng dấu với
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    53

    Có rất ít trường hợp sử dụng thực tế cho

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    49 khi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    50 là số âm. Khi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    50 dương, có rất nhiều và hầu như tất cả chúng đều hữu ích hơn khi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    49 là
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    58. Nếu bây giờ đồng hồ chỉ 10 giờ thì 200 giờ trước nó chỉ mấy giờ?

    Cố gắng tra cứu thuộc tính chữ

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    20 theo cách thông thường sẽ cho a vì dấu chấm được xem là dấu thập phân

    >>> print(x)
    11
    
    6

    Giải pháp là tách chữ khỏi dấu chấm bằng dấu cách hoặc dấu ngoặc đơn

    >>> print(x)
    11
    
    7

    Đối với số nguyên, hãy sử dụng hàm tạo kiểu dựng sẵn, e. g.

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    64. Tương tự, chuyển đổi sang dấu phẩy động, e. g.
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    66

    Theo mặc định, chúng diễn giải số dưới dạng số thập phân, do đó

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    67 đúng và
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    68 tăng.
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    70 lấy cơ sở để chuyển đổi từ làm đối số tùy chọn thứ hai, vì vậy
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    71. Nếu cơ sở được chỉ định là 0, số được diễn giải bằng quy tắc của Python. một '0o' hàng đầu biểu thị bát phân và '0x' biểu thị một số hex

    Không sử dụng chức năng tích hợp nếu tất cả những gì bạn cần là chuyển đổi chuỗi thành số. sẽ chậm hơn đáng kể và có nguy cơ bảo mật. ai đó có thể chuyển cho bạn một biểu thức Python có thể có tác dụng phụ không mong muốn. Ví dụ: ai đó có thể vượt qua

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    74 sẽ xóa thư mục chính của bạn

    cũng có tác dụng diễn giải các số dưới dạng biểu thức Python, do đó e. g.

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    76 đưa ra lỗi cú pháp vì Python không cho phép '0' đứng đầu trong số thập phân (ngoại trừ '0')

    Để chuyển đổi, e. g. , số

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    77 thành chuỗi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    78, sử dụng hàm tạo kiểu có sẵn. Nếu bạn muốn biểu diễn hệ thập lục phân hoặc bát phân, hãy sử dụng các hàm tích hợp sẵn hoặc. Để biết định dạng ưa thích, hãy xem phần và, e. g.
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    82 sản lượng
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    83 và
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    84 sản lượng
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    85

    Bạn không thể, bởi vì các chuỗi là bất biến. Trong hầu hết các trường hợp, bạn chỉ cần tạo một chuỗi mới từ các phần khác nhau mà bạn muốn lắp ráp nó từ đó. Tuy nhiên, nếu bạn cần một đối tượng có khả năng sửa đổi dữ liệu unicode tại chỗ, hãy thử sử dụng một đối tượng hoặc mô-đun

    >>> print(x)
    11
    
    8

    Có nhiều kỹ thuật khác nhau

    • Tốt nhất là sử dụng một từ điển ánh xạ các chuỗi thành các hàm. Ưu điểm chính của kỹ thuật này là các chuỗi không cần khớp với tên của các hàm. Đây cũng là kỹ thuật chính được sử dụng để mô phỏng cấu trúc trường hợp

      >>> print(x)
      11
      
      9

    • Sử dụng chức năng tích hợp

      function_1 has been called
      function_2 has been called
      variable inside function_1
      00

      Lưu ý rằng hoạt động trên bất kỳ đối tượng nào, bao gồm các lớp, thể hiện của lớp, mô-đun, v.v.

      Điều này được sử dụng ở một số nơi trong thư viện tiêu chuẩn, như thế này

      function_1 has been called
      function_2 has been called
      variable inside function_1
      01

    • Sử dụng để phân giải tên hàm

      function_1 has been called
      function_2 has been called
      variable inside function_1
      02

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

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    91 để xóa tất cả các lần xuất hiện của bất kỳ dấu kết thúc dòng nào khỏi cuối chuỗi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    92 mà không xóa khoảng trắng ở cuối khác. Nếu chuỗi
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    92 đại diện cho nhiều hơn một dòng, với một số dòng trống ở cuối, các dấu kết thúc dòng cho tất cả các dòng trống sẽ bị xóa

    function_1 has been called
    function_2 has been called
    variable inside function_1
    03

    Vì điều này thường chỉ được mong muốn khi đọc văn bản từng dòng một, nên sử dụng

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    94 theo cách này hoạt động tốt

    Không phải như vậy

    Để phân tích cú pháp đầu vào đơn giản, cách tiếp cận đơn giản nhất thường là chia dòng thành các từ được phân tách bằng khoảng trắng bằng cách sử dụng phương thức của đối tượng chuỗi, sau đó chuyển đổi chuỗi thập phân thành giá trị số bằng cách sử dụng hoặc.

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    95 hỗ trợ tham số “sep” tùy chọn, hữu ích nếu dòng sử dụng thứ gì đó không phải khoảng trắng làm dấu phân cách

    Để phân tích cú pháp đầu vào phức tạp hơn, các biểu thức chính quy mạnh hơn

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    99 của C và phù hợp hơn cho tác vụ

    xem

    Chuỗi thô kết thúc bằng số lẻ dấu gạch chéo ngược sẽ thoát khỏi dấu ngoặc kép của chuỗi

    function_1 has been called
    function_2 has been called
    variable inside function_1
    04

    Có một số cách giải quyết cho việc này. Một là sử dụng các chuỗi thông thường và nhân đôi dấu gạch chéo ngược

    function_1 has been called
    function_2 has been called
    variable inside function_1
    05

    Một cách khác là nối một chuỗi thông thường có dấu gạch chéo ngược đã thoát vào chuỗi thô

    function_1 has been called
    function_2 has been called
    variable inside function_1
    06

    Cũng có thể sử dụng để nối thêm dấu gạch chéo ngược trên Windows

    function_1 has been called
    function_2 has been called
    variable inside function_1
    07

    Lưu ý rằng mặc dù dấu gạch chéo ngược sẽ "thoát" một trích dẫn nhằm mục đích xác định vị trí kết thúc của chuỗi thô, nhưng không có dấu gạch chéo ngược nào xảy ra khi diễn giải giá trị của chuỗi thô. Nghĩa là, dấu gạch chéo ngược vẫn hiện diện trong giá trị của chuỗi thô

    function_1 has been called
    function_2 has been called
    variable inside function_1
    08

    Cũng xem thông số kỹ thuật trong

    Đó là một khó khăn, nói chung. Đầu tiên, đây là danh sách những điều cần nhớ trước khi đi sâu hơn

    • Các đặc điểm hiệu suất khác nhau giữa các triển khai Python. Câu hỏi thường gặp này tập trung vào

    • Hành vi có thể khác nhau giữa các hệ điều hành, đặc biệt khi nói về I/O hoặc đa luồng

    • Bạn phải luôn tìm các điểm nóng trong chương trình của mình trước khi cố gắng tối ưu hóa bất kỳ mã nào (xem mô-đun)

    • Viết tập lệnh điểm chuẩn sẽ cho phép bạn lặp lại nhanh chóng khi tìm kiếm các cải tiến (xem mô-đun)

    • Bạn nên có phạm vi mã tốt (thông qua thử nghiệm đơn vị hoặc bất kỳ kỹ thuật nào khác) trước khi có khả năng giới thiệu hồi quy ẩn trong các tối ưu hóa tinh vi

    Điều đó đang được nói, có rất nhiều thủ thuật để tăng tốc mã Python. Dưới đây là một số nguyên tắc chung cần thiết để đạt được mức hiệu suất chấp nhận được

    • Làm cho thuật toán của bạn nhanh hơn (hoặc thay đổi thành thuật toán nhanh hơn) có thể mang lại lợi ích lớn hơn nhiều so với việc cố gắng rải các thủ thuật tối ưu hóa vi mô lên toàn bộ mã của bạn

    • Sử dụng đúng cấu trúc dữ liệu. Nghiên cứu tài liệu cho các và mô-đun

    • Khi thư viện tiêu chuẩn cung cấp một nguyên hàm để làm một việc gì đó, có khả năng (mặc dù không được đảm bảo) sẽ nhanh hơn bất kỳ giải pháp thay thế nào mà bạn có thể nghĩ ra. Điều này hoàn toàn đúng đối với các nguyên thủy được viết bằng C, chẳng hạn như nội trang và một số loại tiện ích mở rộng. Ví dụ: đảm bảo sử dụng phương thức tích hợp sẵn hoặc chức năng liên quan để thực hiện sắp xếp (và xem ví dụ về cách sử dụng nâng cao vừa phải)

    • Sự trừu tượng hóa có xu hướng tạo ra sự gián tiếp và buộc trình thông dịch phải làm việc nhiều hơn. Nếu mức độ gián tiếp lớn hơn số lượng công việc hữu ích được thực hiện, chương trình của bạn sẽ chậm hơn. Bạn nên tránh sự trừu tượng quá mức, đặc biệt là dưới dạng các hàm hoặc phương thức nhỏ (cũng thường gây bất lợi cho khả năng đọc)

    Nếu bạn đã đạt đến giới hạn mà Python thuần túy có thể cho phép, sẽ có những công cụ giúp bạn tiến xa hơn. Ví dụ: Cython có thể biên dịch phiên bản mã Python được sửa đổi một chút thành phần mở rộng C và có thể được sử dụng trên nhiều nền tảng khác nhau. Cython có thể tận dụng quá trình biên dịch (và các chú thích loại tùy chọn) để làm cho mã của bạn nhanh hơn đáng kể so với khi diễn giải. Nếu bạn tự tin vào kỹ năng lập trình C của mình, bạn cũng có thể tự

    Xem thêm

    Trang wiki dành cho mẹo hiệu suất

    và các đối tượng là bất biến, do đó việc nối nhiều chuỗi lại với nhau là không hiệu quả vì mỗi lần nối tạo ra một đối tượng mới. Trong trường hợp chung, tổng chi phí thời gian chạy là bậc hai trong tổng độ dài chuỗi

    Để tích lũy nhiều đối tượng, thành ngữ được đề xuất là đặt chúng vào một danh sách và gọi ở cuối

    function_1 has been called
    function_2 has been called
    variable inside function_1
    09

    (một thành ngữ hợp lý hiệu quả khác là sử dụng )

    Để tích lũy nhiều đối tượng, thành ngữ được khuyến nghị là mở rộng một đối tượng bằng cách sử dụng phép nối tại chỗ (toán tử

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    10)

    function_1 has been called
    function_2 has been called
    variable inside function_1
    40

    Hàm tạo kiểu

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    14 chuyển đổi bất kỳ chuỗi nào (thực tế là bất kỳ có thể lặp lại nào) thành một bộ có cùng các mục theo cùng một thứ tự

    Ví dụ:

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    15 mang lại
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    16 và
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    17 mang lại
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    18. Nếu đối số là một bộ, thì nó không tạo một bản sao mà trả về cùng một đối tượng, vì vậy sẽ rẻ hơn nếu bạn không chắc chắn rằng một đối tượng đã là một bộ

    Hàm tạo kiểu

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    20 chuyển đổi bất kỳ chuỗi nào hoặc có thể lặp lại thành một danh sách có cùng mục theo cùng một thứ tự. Ví dụ:
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    21 mang lại
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    22 và
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    23 mang lại
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    24. Nếu đối số là một danh sách, nó sẽ tạo một bản sao giống như
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    25

    Chuỗi Python được lập chỉ mục với số dương và số âm. Đối với các số dương 0 là chỉ số đầu tiên 1 là chỉ số thứ hai, v.v. Đối với các chỉ số âm -1 là chỉ số cuối cùng và -2 là chỉ số áp chót (kế tiếp đến cuối cùng), v.v. Hãy nghĩ về

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    26 giống như
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    27

    Sử dụng chỉ số âm có thể rất thuận tiện. Ví dụ:

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    28 là tất cả của chuỗi ngoại trừ ký tự cuối cùng của nó, rất hữu ích để xóa dòng mới ở cuối chuỗi

    Sử dụng chức năng tích hợp

    function_1 has been called
    function_2 has been called
    variable inside function_1
    41

    Điều này sẽ không chạm vào trình tự ban đầu của bạn, nhưng tạo một bản sao mới với thứ tự đảo ngược để lặp lại

    Xem Sách dạy nấu ăn Python để biết một cuộc thảo luận dài về nhiều cách để thực hiện việc này

    https. //mã số. trạng thái kích hoạt. com/công thức nấu ăn/52560/

    Nếu bạn không ngại sắp xếp lại danh sách, hãy sắp xếp nó rồi quét từ cuối danh sách, xóa các mục trùng lặp khi bạn thực hiện

    function_1 has been called
    function_2 has been called
    variable inside function_1
    42

    Nếu tất cả các phần tử của danh sách có thể được sử dụng làm khóa thiết lập (i. e. họ là tất cả) điều này thường nhanh hơn

    function_1 has been called
    function_2 has been called
    variable inside function_1
    43

    Điều này chuyển đổi danh sách thành một tập hợp, do đó loại bỏ các bản sao và sau đó quay lại danh sách

    Như với việc loại bỏ các bản sao, lặp lại rõ ràng ngược lại với điều kiện xóa là một khả năng. Tuy nhiên, sẽ dễ dàng và nhanh hơn khi sử dụng thay thế lát cắt bằng phép lặp chuyển tiếp rõ ràng hoặc ẩn. Đây là ba biến thể

    function_1 has been called
    function_2 has been called
    variable inside function_1
    44

    Việc hiểu danh sách có thể nhanh nhất

    Sử dụng một danh sách

    function_1 has been called
    function_2 has been called
    variable inside function_1
    45

    Các danh sách tương đương với các mảng C hoặc Pascal về độ phức tạp về thời gian của chúng;

    Mô-đun

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    87 cũng cung cấp các phương thức để tạo các mảng có loại cố định với các biểu diễn nhỏ gọn, nhưng chúng chậm hơn để lập chỉ mục so với danh sách. Cũng lưu ý rằng NumPy và các gói bên thứ ba khác cũng xác định các cấu trúc giống như mảng với các đặc điểm khác nhau

    Để có danh sách được liên kết kiểu Lisp, bạn có thể mô phỏng các ô khuyết điểm bằng cách sử dụng các bộ dữ liệu

    function_1 has been called
    function_2 has been called
    variable inside function_1
    46

    Nếu muốn có khả năng thay đổi, bạn có thể sử dụng danh sách thay vì bộ dữ liệu. Ở đây, dạng tương tự của ô tô Lisp là

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    31 và dạng tương tự của cdr là
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    32. Chỉ làm điều này nếu bạn chắc chắn rằng mình thực sự cần, vì nó thường chậm hơn rất nhiều so với việc sử dụng danh sách Python

    Có thể bạn đã thử tạo một mảng nhiều chiều như thế này

    function_1 has been called
    function_2 has been called
    variable inside function_1
    47

    Điều này có vẻ đúng nếu bạn in nó

    function_1 has been called
    function_2 has been called
    variable inside function_1
    48

    Nhưng khi bạn chỉ định một giá trị, nó sẽ hiển thị ở nhiều nơi

    function_1 has been called
    function_2 has been called
    variable inside function_1
    49

    Lý do là sao chép danh sách với

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    68 không tạo bản sao, nó chỉ tạo tham chiếu đến các đối tượng hiện có.
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    34 tạo một danh sách chứa 3 tham chiếu đến cùng một danh sách có độ dài hai. Các thay đổi đối với một hàng sẽ hiển thị trong tất cả các hàng, điều này gần như chắc chắn không phải là điều bạn muốn

    Cách tiếp cận được đề xuất là trước tiên hãy tạo một danh sách có độ dài mong muốn và sau đó điền vào từng phần tử bằng một danh sách mới được tạo

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    20

    Điều này tạo ra một danh sách chứa 3 danh sách khác nhau có độ dài hai. Bạn cũng có thể sử dụng cách hiểu danh sách

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    21

    Hoặc, bạn có thể sử dụng tiện ích mở rộng cung cấp kiểu dữ liệu ma trận;

    Để gọi một phương thức hoặc hàm và tích lũy các giá trị trả về là một danh sách, a là một giải pháp tao nhã

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    22

    Để chỉ chạy phương thức hoặc hàm mà không lưu các giá trị trả về, một vòng lặp đơn giản là đủ

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    23

    Điều này là do sự kết hợp của thực tế là các toán tử gán tăng cường là các toán tử gán và sự khác biệt giữa các đối tượng có thể thay đổi và không thể thay đổi trong Python

    Cuộc thảo luận này áp dụng chung khi các toán tử gán tăng cường được áp dụng cho các phần tử của bộ trỏ đến các đối tượng có thể thay đổi, nhưng chúng tôi sẽ sử dụng

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    16 và
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    10 làm ví dụ của chúng tôi

    Nếu bạn đã viết

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    24

    Lý do ngoại lệ phải rõ ràng ngay lập tức.

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    33 được thêm vào đối tượng
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    39 trỏ đến (
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    33), tạo ra đối tượng kết quả,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    51, nhưng khi chúng tôi cố gắng gán kết quả tính toán,
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    51, cho phần tử
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    32 của bộ dữ liệu, chúng tôi gặp lỗi vì chúng tôi không thể

    Dưới vỏ bọc, điều mà câu lệnh gán tăng cường này đang thực hiện là xấp xỉ điều này

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    25

    Đó là phần gán của hoạt động tạo ra lỗi, vì một bộ dữ liệu là bất biến

    Khi bạn viết một cái gì đó như

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    26

    Ngoại lệ đáng ngạc nhiên hơn một chút và thậm chí còn đáng ngạc nhiên hơn là mặc dù có lỗi nhưng phần bổ sung vẫn hoạt động

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    27

    Để biết tại sao điều này xảy ra, bạn cần biết rằng (a) nếu một đối tượng triển khai một phương thức ma thuật, nó sẽ được gọi khi phép gán tăng cường

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    10 được thực thi và giá trị trả về của nó là giá trị được sử dụng trong câu lệnh gán; . Đó là lý do tại sao chúng tôi nói rằng đối với danh sách,
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    10 là “viết tắt” của
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    49

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    28

    Điều này tương đương với

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    29

    Đối tượng được trỏ tới bởi a_list đã bị thay đổi và con trỏ tới đối tượng bị thay đổi được gán lại cho

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    13. Kết quả cuối cùng của phép gán là không hoạt động, vì nó là một con trỏ tới cùng một đối tượng mà trước đó
    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    13 đã trỏ tới, nhưng phép gán vẫn diễn ra

    Do đó, trong ví dụ bộ dữ liệu của chúng tôi, những gì đang xảy ra tương đương với

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    90

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    44 thành công và do đó danh sách được mở rộng, nhưng mặc dù
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    53 trỏ đến cùng một đối tượng mà
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    39 đã trỏ đến, phép gán cuối cùng đó vẫn dẫn đến lỗi, bởi vì các bộ dữ liệu là bất biến

    Kỹ thuật này, do Randal Schwartz của cộng đồng Perl, sắp xếp các phần tử của danh sách theo một số liệu ánh xạ từng phần tử tới “giá trị sắp xếp” của nó. Trong Python, sử dụng đối số

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    55 cho phương thức

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    91

    Hợp nhất chúng thành một bộ lặp gồm các bộ, sắp xếp danh sách kết quả, sau đó chọn ra phần tử bạn muốn

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    92

    Một lớp là loại đối tượng cụ thể được tạo bằng cách thực hiện một câu lệnh lớp. Các đối tượng lớp được sử dụng làm mẫu để tạo các đối tượng thể hiện, thể hiện cả dữ liệu (thuộc tính) và mã (phương thức) cụ thể cho một kiểu dữ liệu

    Một lớp có thể dựa trên một hoặc nhiều lớp khác, được gọi là (các) lớp cơ sở của nó. Sau đó, nó kế thừa các thuộc tính và phương thức của các lớp cơ sở của nó. Điều này cho phép một mô hình đối tượng được tinh chỉnh liên tục bằng kế thừa. Bạn có thể có một lớp

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    57 chung cung cấp các phương thức truy cập cơ bản cho hộp thư và các lớp con như
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    58,
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    59,
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    60 xử lý các định dạng hộp thư cụ thể khác nhau

    Một phương thức là một chức năng trên một số đối tượng

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 mà bạn thường gọi là
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    62. Các phương thức được định nghĩa là các hàm bên trong định nghĩa lớp

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    93

    Bản thân chỉ là một tên quy ước cho đối số đầu tiên của một phương thức. Một phương thức được định nghĩa là ________ 863 nên được gọi là

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    64 đối với một số trường hợp
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 của lớp mà định nghĩa xảy ra;

    Xem thêm

    Sử dụng chức năng tích hợp. Bạn có thể kiểm tra xem một đối tượng có phải là một thể hiện của bất kỳ lớp nào hay không bằng cách cung cấp một bộ thay vì một lớp đơn lẻ, e. g.

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    68 và cũng có thể kiểm tra xem một đối tượng có phải là một trong các loại dựng sẵn của Python hay không, e. g.
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    69 hoặc
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    70

    Lưu ý rằng cũng kiểm tra kế thừa ảo từ một. Vì vậy, bài kiểm tra sẽ trả về

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    72 cho một lớp đã đăng ký ngay cả khi không được kế thừa trực tiếp hoặc gián tiếp từ nó. Để kiểm tra "sự kế thừa thực sự", hãy quét lớp

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    94

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    95

    Lưu ý rằng hầu hết các chương trình không thường xuyên sử dụng trên các lớp do người dùng định nghĩa. Nếu bạn đang tự phát triển các lớp, thì một kiểu hướng đối tượng phù hợp hơn là định nghĩa các phương thức trên các lớp đóng gói một hành vi cụ thể, thay vì kiểm tra lớp của đối tượng và thực hiện một việc khác dựa trên lớp đó là gì. Ví dụ: nếu bạn có một chức năng thực hiện điều gì đó

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    96

    Một cách tiếp cận tốt hơn là định nghĩa một phương thức

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    74 trên tất cả các lớp và chỉ cần gọi nó là

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    97

    Ủy quyền là một kỹ thuật hướng đối tượng (còn được gọi là mẫu thiết kế). Giả sử bạn có một đối tượng

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24 và muốn thay đổi hành vi của chỉ một trong các phương thức của nó. Bạn có thể tạo một lớp mới cung cấp cách triển khai mới cho phương thức mà bạn muốn thay đổi và ủy quyền tất cả các phương thức khác cho phương thức tương ứng của
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    24

    Các lập trình viên Python có thể dễ dàng thực hiện ủy quyền. Ví dụ, lớp sau triển khai một lớp hoạt động như một tệp nhưng chuyển đổi tất cả dữ liệu được viết thành chữ hoa

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    98

    Ở đây, lớp

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    77 định nghĩa lại phương thức
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    78 để chuyển đổi chuỗi đối số thành chữ hoa trước khi gọi phương thức
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    79 bên dưới. Tất cả các phương thức khác được ủy quyền cho đối tượng
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    80 bên dưới. Việc ủy ​​quyền được thực hiện thông qua phương pháp;

    Lưu ý rằng đối với các trường hợp tổng quát hơn, việc ủy ​​quyền có thể phức tạp hơn. Khi các thuộc tính phải được đặt cũng như được truy xuất, lớp cũng phải định nghĩa một phương thức và nó phải thực hiện cẩn thận. Việc triển khai cơ bản của

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    82 gần tương đương như sau

    >>> x = 10
    >>> def bar():
    ..     print(x)
    ...
    >>> bar()
    10
    
    99

    Hầu hết các triển khai

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    82 phải sửa đổi để tự lưu trữ trạng thái cục bộ mà không gây ra đệ quy vô hạn

    Sử dụng chức năng tích hợp

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    10

    Trong ví dụ này, sẽ tự động xác định phiên bản mà nó được gọi (giá trị

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    88), tra cứu (MRO) với
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    89 và trả về dòng tiếp theo sau
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    90 trong MRO.
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    91

    Bạn có thể gán lớp cơ sở cho một bí danh và lấy từ bí danh. Sau đó, tất cả những gì bạn phải thay đổi là giá trị được gán cho bí danh. Ngẫu nhiên, thủ thuật này cũng hữu ích nếu bạn muốn quyết định động (e. g. tùy thuộc vào sự sẵn có của tài nguyên) nên sử dụng lớp cơ sở nào. Ví dụ

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    11

    Cả dữ liệu tĩnh và phương thức tĩnh (theo nghĩa của C++ hoặc Java) đều được hỗ trợ trong Python

    Đối với dữ liệu tĩnh, chỉ cần xác định thuộc tính lớp. Để gán một giá trị mới cho thuộc tính, bạn phải sử dụng rõ ràng tên lớp trong phép gán

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    12

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    92 cũng đề cập đến
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    93 cho bất kỳ
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    94 nào mà
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    95 nắm giữ, trừ khi bị ghi đè bởi chính
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    94 hoặc bởi một số lớp trên đường dẫn tìm kiếm lớp cơ sở từ
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    97 trở lại
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    98

    thận trọng. trong một phương thức của C, một phép gán như

    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    99 sẽ tạo ra một thể hiện mới và không liên quan có tên là "đếm" theo lệnh riêng của
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    88. Rebinding tên dữ liệu tĩnh của lớp phải luôn chỉ định lớp cho dù có bên trong phương thức hay không

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    13

    Phương pháp tĩnh là có thể

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    14

    Tuy nhiên, một cách đơn giản hơn nhiều để có được tác dụng của một phương thức tĩnh là thông qua một hàm cấp mô-đun đơn giản

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    15

    Nếu mã của bạn được cấu trúc để xác định một lớp (hoặc hệ thống phân cấp lớp có liên quan chặt chẽ) cho mỗi mô-đun, điều này sẽ cung cấp khả năng đóng gói mong muốn

    Câu trả lời này thực sự áp dụng cho tất cả các phương thức, nhưng câu hỏi thường xuất hiện đầu tiên trong ngữ cảnh của hàm tạo

    Trong C++ bạn sẽ viết

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    16

    Trong Python, bạn phải viết một hàm tạo duy nhất nắm bắt tất cả các trường hợp bằng các đối số mặc định. Ví dụ

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    17

    Điều này không hoàn toàn tương đương, nhưng đủ gần trong thực tế

    Bạn cũng có thể thử danh sách đối số có độ dài thay đổi, e. g

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    18

    Cách tiếp cận tương tự hoạt động cho tất cả các định nghĩa phương thức

    Các tên biến có hai dấu gạch dưới ở đầu được "xáo trộn" để cung cấp một cách đơn giản nhưng hiệu quả để xác định các biến riêng của lớp. Bất kỳ mã định danh nào có dạng

    >>> print(x)
    11
    
    01 (ít nhất hai dấu gạch dưới ở đầu, nhiều nhất là một dấu gạch dưới ở cuối) được thay thế bằng văn bản bằng
    >>> print(x)
    11
    
    02, trong đó
    >>> print(x)
    11
    
    03 là tên lớp hiện tại với bất kỳ dấu gạch dưới ở đầu nào bị loại bỏ

    Điều này không đảm bảo quyền riêng tư. người dùng bên ngoài vẫn có thể cố ý truy cập vào thuộc tính “_classname__spam” và các giá trị riêng tư được hiển thị trong đối tượng

    >>> print(x)
    11
    
    04. Nhiều lập trình viên Python không bao giờ bận tâm đến việc sử dụng tên biến riêng

    Có một số lý do có thể cho việc này

    Câu lệnh không nhất thiết phải gọi - nó chỉ đơn giản là giảm số lượng tham chiếu của đối tượng và nếu giá trị này bằng 0 thì

    >>> print(x)
    11
    
    06 được gọi

    Nếu cấu trúc dữ liệu của bạn chứa các liên kết vòng (e. g. một cây trong đó mỗi đứa trẻ có một tham chiếu gốc và mỗi cha mẹ có một danh sách con) thì số lượng tham chiếu sẽ không bao giờ trở về 0. Thỉnh thoảng, Python chạy một thuật toán để phát hiện các chu trình như vậy, nhưng bộ thu gom rác có thể chạy một thời gian sau khi tham chiếu cuối cùng đến cấu trúc dữ liệu của bạn biến mất, vì vậy phương thức

    >>> print(x)
    11
    
    06 của bạn có thể được gọi vào thời điểm bất tiện và ngẫu nhiên. Điều này thật bất tiện nếu bạn đang cố tái tạo sự cố. Tồi tệ hơn, thứ tự thực hiện các phương thức
    >>> print(x)
    11
    
    06 của đối tượng là tùy ý. Bạn có thể chạy để bắt buộc thu thập, nhưng có những trường hợp bệnh lý mà các đối tượng sẽ không bao giờ được thu thập

    Mặc dù có trình thu thập chu trình, bạn vẫn nên xác định một phương thức

    >>> print(x)
    11
    
    11 rõ ràng trên các đối tượng sẽ được gọi bất cứ khi nào bạn hoàn thành chúng. Phương thức
    >>> print(x)
    11
    
    11 sau đó có thể xóa các thuộc tính đề cập đến các đối tượng con. Không gọi trực tiếp
    >>> print(x)
    11
    
    06 –
    >>> print(x)
    11
    
    06 nên gọi
    >>> print(x)
    11
    
    11 và
    >>> print(x)
    11
    
    11 phải đảm bảo rằng nó có thể được gọi nhiều lần cho cùng một đối tượng

    Một cách khác để tránh các tham chiếu theo chu kỳ là sử dụng mô-đun, cho phép bạn trỏ đến các đối tượng mà không cần tăng số lượng tham chiếu của chúng. Ví dụ, các cấu trúc dữ liệu dạng cây nên sử dụng các tham chiếu yếu cho các tham chiếu cha và anh chị em của chúng (nếu chúng cần. )

    Cuối cùng, nếu phương thức

    >>> print(x)
    11
    
    06 của bạn đưa ra một ngoại lệ, một thông báo cảnh báo sẽ được in ra

    Python không theo dõi tất cả các phiên bản của một lớp (hoặc của một kiểu dựng sẵn). Bạn có thể lập trình hàm tạo của lớp để theo dõi tất cả các phiên bản bằng cách giữ một danh sách các tham chiếu yếu cho từng phiên bản

    Nội dung trả về một số nguyên được đảm bảo là duy nhất trong suốt thời gian tồn tại của đối tượng. Vì trong CPython, đây là địa chỉ bộ nhớ của đối tượng, điều thường xảy ra là sau khi một đối tượng bị xóa khỏi bộ nhớ, đối tượng mới được tạo tiếp theo sẽ được cấp phát ở cùng một vị trí trong bộ nhớ. Điều này được minh họa bằng ví dụ này

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    19

    Hai id thuộc về các đối tượng số nguyên khác nhau được tạo trước đó và bị xóa ngay sau khi thực hiện lệnh gọi

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    19. Để chắc chắn rằng các đối tượng có id mà bạn muốn kiểm tra vẫn còn tồn tại, hãy tạo một tham chiếu khác đến đối tượng

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    00

    Toán tử

    >>> foo()
    Traceback (most recent call last):
      ...
    UnboundLocalError: local variable 'x' referenced before assignment
    
    22 kiểm tra danh tính đối tượng. Bài kiểm tra
    >>> print(x)
    11
    
    24 tương đương với
    >>> print(x)
    11
    
    25

    Thuộc tính quan trọng nhất của kiểm tra danh tính là một đối tượng luôn giống với chính nó,

    >>> print(x)
    11
    
    26 luôn trả về
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    72. Kiểm tra danh tính thường nhanh hơn kiểm tra đẳng thức. Và không giống như các bài kiểm tra đẳng thức, các bài kiểm tra danh tính được đảm bảo trả về giá trị boolean
    >>> x = 10
    >>> def foobar():
    ..     global x
    ..     print(x)
    ..     x += 1
    ...
    >>> foobar()
    10
    
    72 hoặc
    >>> print(x)
    11
    
    29

    Tuy nhiên, các bài kiểm tra nhận dạng chỉ có thể được thay thế cho các bài kiểm tra đẳng thức khi nhận dạng đối tượng được đảm bảo. Nói chung, có ba trường hợp mà danh tính được đảm bảo

    1) Bài tập tạo tên mới nhưng không thay đổi nhận dạng đối tượng. Sau khi chuyển nhượng

    >>> print(x)
    11
    
    30, đảm bảo rằng
    >>> print(x)
    11
    
    31

    2) Đặt một đối tượng vào vùng chứa lưu trữ các tham chiếu đối tượng không thay đổi danh tính đối tượng. Sau khi gán danh sách

    >>> print(x)
    11
    
    32, đảm bảo rằng
    >>> print(x)
    11
    
    33

    3) Nếu một đối tượng là một singleton, điều đó có nghĩa là chỉ có thể tồn tại một phiên bản của đối tượng đó. Sau khi gán

    >>> print(x)
    11
    
    34 và
    >>> print(x)
    11
    
    35, đảm bảo rằng
    >>> print(x)
    11
    
    24 vì
    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65 là một singleton

    Trong hầu hết các trường hợp khác, các bài kiểm tra danh tính là không nên và các bài kiểm tra bình đẳng được ưa thích hơn. Cụ thể, không nên sử dụng các kiểm tra nhận dạng để kiểm tra các hằng số như và không được đảm bảo là đơn lẻ

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    01

    Tương tự như vậy, các phiên bản mới của vùng chứa có thể thay đổi không bao giờ giống hệt nhau

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    02

    Trong mã thư viện tiêu chuẩn, bạn sẽ thấy một số mẫu phổ biến để sử dụng chính xác các bài kiểm tra danh tính

    1) Theo khuyến nghị của PEP 8, kiểm tra danh tính là cách ưu tiên để kiểm tra

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65. Điều này đọc giống như tiếng Anh đơn giản trong mã và tránh nhầm lẫn với các đối tượng khác có thể có giá trị boolean đánh giá sai

    2) Việc phát hiện các đối số tùy chọn có thể phức tạp khi

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    65 là giá trị đầu vào hợp lệ. Trong những tình huống đó, bạn có thể tạo một đối tượng canh gác đơn lẻ được đảm bảo khác biệt với các đối tượng khác. Ví dụ: đây là cách triển khai một phương thức hoạt động như

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    03

    3) Việc triển khai vùng chứa đôi khi cần tăng cường kiểm tra tính bình đẳng bằng kiểm tra danh tính. Điều này giúp mã không bị nhầm lẫn bởi các đối tượng như

    >>> print(x)
    11
    
    43 không bằng chính chúng

    Ví dụ, đây là triển khai của

    >>> print(x)
    11
    
    44

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    04

    Khi phân lớp một loại bất biến, hãy ghi đè phương thức thay vì phương thức. Cái sau chỉ chạy sau khi một phiên bản được tạo, quá muộn để thay đổi dữ liệu trong một phiên bản không thay đổi

    Tất cả các lớp bất biến này có chữ ký khác với lớp cha của chúng

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    05

    Các lớp có thể được sử dụng như thế này

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    06

    Hai công cụ chính cho các phương pháp lưu trữ là và. Cái trước lưu trữ kết quả ở cấp độ thể hiện và cái sau ở cấp độ lớp

    Cách tiếp cận cached_property chỉ hoạt động với các phương thức không nhận bất kỳ đối số nào. Nó không tạo một tham chiếu đến thể hiện. Kết quả của phương thức được lưu trong bộ nhớ cache sẽ chỉ được lưu giữ miễn là phiên bản còn tồn tại

    Ưu điểm là khi một instance không còn được sử dụng, kết quả của phương thức đã lưu trong bộ nhớ cache sẽ được giải phóng ngay lập tức. Nhược điểm là nếu các trường hợp tích lũy, thì phương thức tích lũy cũng sẽ dẫn đến kết quả. Họ có thể phát triển mà không bị ràng buộc

    Cách tiếp cận lru_cache hoạt động với các phương thức có đối số có thể băm. Nó tạo một tham chiếu đến thể hiện trừ khi có những nỗ lực đặc biệt để chuyển vào các tham chiếu yếu

    Ưu điểm của thuật toán ít được sử dụng gần đây nhất là bộ đệm được giới hạn bởi kích thước tối đa được chỉ định. Điểm bất lợi là các phiên bản được giữ nguyên cho đến khi hết bộ nhớ cache hoặc cho đến khi bộ nhớ cache bị xóa

    Ví dụ này cho thấy các kỹ thuật khác nhau

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    07

    Ví dụ trên giả định rằng station_id không bao giờ thay đổi. Nếu các thuộc tính phiên bản có liên quan có thể thay đổi, thì phương pháp cached_property không thể hoạt động vì nó không thể phát hiện các thay đổi đối với các thuộc tính

    Để làm cho cách tiếp cận lru_cache hoạt động khi station_id có thể thay đổi, lớp cần xác định các phương thức và để bộ đệm có thể phát hiện các cập nhật thuộc tính có liên quan

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    08

    Khi một mô-đun được nhập lần đầu tiên (hoặc khi tệp nguồn đã thay đổi kể từ khi tệp được biên dịch hiện tại được tạo), tệp

    >>> print(x)
    11
    
    51 chứa mã đã biên dịch phải được tạo trong thư mục con
    >>> print(x)
    11
    
    52 của thư mục chứa tệp
    >>> print(x)
    11
    
    53. Tệp
    >>> print(x)
    11
    
    51 sẽ có tên tệp bắt đầu bằng tên giống như tệp
    >>> print(x)
    11
    
    53 và kết thúc bằng
    >>> print(x)
    11
    
    51, với thành phần ở giữa phụ thuộc vào tệp nhị phân
    >>> print(x)
    11
    
    57 cụ thể đã tạo ra nó. (Xem PEP 3147 để biết chi tiết. )

    Một lý do khiến tệp

    >>> print(x)
    11
    
    51 không thể được tạo là vấn đề về quyền đối với thư mục chứa tệp nguồn, nghĩa là không thể tạo thư mục con
    >>> print(x)
    11
    
    52. Ví dụ: điều này có thể xảy ra nếu bạn phát triển với tư cách người dùng này nhưng chạy với tư cách người dùng khác, chẳng hạn như nếu bạn đang thử nghiệm với máy chủ web

    Trừ khi biến môi trường được đặt, việc tạo một. pyc là tự động nếu bạn đang nhập một mô-đun và Python có khả năng (quyền, dung lượng trống, v.v.) để tạo thư mục con

    >>> print(x)
    11
    
    52 và ghi mô-đun đã biên dịch vào thư mục con đó

    Chạy Python trên tập lệnh cấp cao nhất không được coi là nhập và sẽ không có

    >>> print(x)
    11
    
    51 nào được tạo. Ví dụ: nếu bạn có mô-đun cấp cao nhất
    >>> print(x)
    11
    
    63 nhập mô-đun khác
    >>> print(x)
    11
    
    64, khi bạn chạy
    >>> print(x)
    11
    
    65 (bằng cách nhập
    >>> print(x)
    11
    
    66 dưới dạng lệnh trình bao), một
    >>> print(x)
    11
    
    51 sẽ được tạo cho
    >>> print(x)
    11
    
    68 vì
    >>> print(x)
    11
    
    68 được nhập, nhưng sẽ không có tệp
    >>> print(x)
    11
    
    51 nào được nhập

    Nếu bạn cần tạo tệp

    >>> print(x)
    11
    
    51 cho
    >>> print(x)
    11
    
    65 – nghĩa là tạo tệp
    >>> print(x)
    11
    
    51 cho mô-đun không được nhập – bạn có thể sử dụng và mô-đun

    Mô-đun có thể tự biên dịch bất kỳ mô-đun nào. Một cách là sử dụng hàm

    >>> print(x)
    11
    
    79 trong mô-đun đó một cách tương tác

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    09

    Thao tác này sẽ ghi

    >>> print(x)
    11
    
    51 vào thư mục con
    >>> print(x)
    11
    
    52 ở cùng vị trí với
    >>> print(x)
    11
    
    63 (hoặc bạn có thể ghi đè lên thư mục đó bằng tham số tùy chọn
    >>> print(x)
    11
    
    83)

    Bạn cũng có thể tự động biên dịch tất cả các tệp trong một thư mục hoặc thư mục bằng cách sử dụng mô-đun. Bạn có thể làm điều đó từ dấu nhắc trình bao bằng cách chạy

    >>> print(x)
    11
    
    85 và cung cấp đường dẫn của thư mục chứa các tệp Python để biên dịch

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    10

    Một mô-đun có thể tìm ra tên mô-đun của chính nó bằng cách xem biến toàn cục được xác định trước

    >>> print(x)
    11
    
    86. Nếu giá trị này có giá trị
    >>> print(x)
    11
    
    87, chương trình đang chạy dưới dạng tập lệnh. Nhiều mô-đun thường được sử dụng bằng cách nhập chúng cũng cung cấp giao diện dòng lệnh hoặc tự kiểm tra và chỉ thực thi mã này sau khi kiểm tra
    >>> print(x)
    11
    
    86

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    11

    Giả sử bạn có các mô-đun sau

    >>> print(x)
    11
    
    63

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    12

    >>> print(x)
    11
    
    90

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    13

    Vấn đề là trình thông dịch sẽ thực hiện các bước sau

    • nhập khẩu chính

      >>> print(x)
      11
      
      65

    • Toàn cầu trống cho

      >>> print(x)
      11
      
      65 được tạo

    • >>> print(x)
      11
      
      65 được biên dịch và bắt đầu thực thi

    • >>> print(x)
      11
      
      65 nhập khẩu
      >>> print(x)
      11
      
      95

    • Toàn cầu trống cho

      >>> print(x)
      11
      
      95 được tạo

    • >>> print(x)
      11
      
      95 được biên dịch và bắt đầu thực thi

    • >>> print(x)
      11
      
      95 nhập khẩu
      >>> print(x)
      11
      
      65 (không hoạt động vì đã có một mô-đun tên là
      >>> print(x)
      11
      
      65)

    • Cơ chế nhập cố gắng đọc

      function_1 has been called
      function_2 has been called
      variable inside function_1
      001 từ toàn cầu
      >>> print(x)
      11
      
      65, để đặt
      function_1 has been called
      function_2 has been called
      variable inside function_1
      003

    Bước cuối cùng không thành công, vì Python vẫn chưa hoàn thành việc diễn giải

    >>> print(x)
    11
    
    65 và từ điển ký hiệu chung cho
    >>> print(x)
    11
    
    65 vẫn còn trống

    Điều tương tự cũng xảy ra khi bạn sử dụng

    function_1 has been called
    function_2 has been called
    variable inside function_1
    006, sau đó thử truy cập
    function_1 has been called
    function_2 has been called
    variable inside function_1
    007 bằng mã toàn cầu

    Có (ít nhất) ba cách giải quyết khả thi cho sự cố này

    Guido van Rossum khuyên bạn nên tránh tất cả việc sử dụng

    function_1 has been called
    function_2 has been called
    variable inside function_1
    008 và đặt tất cả mã bên trong các chức năng. Việc khởi tạo biến toàn cục và biến lớp chỉ nên sử dụng hằng hoặc hàm tích hợp. Điều này có nghĩa là mọi thứ từ mô-đun đã nhập được tham chiếu là
    function_1 has been called
    function_2 has been called
    variable inside function_1
    009

    Jim Roskind gợi ý thực hiện các bước theo thứ tự sau trong mỗi mô-đun

    • xuất (toàn cục, hàm và lớp không cần các lớp cơ sở đã nhập)

    • câu lệnh

      function_1 has been called
      function_2 has been called
      variable inside function_1
      010

    • mã hoạt động (bao gồm toàn cầu được khởi tạo từ các giá trị đã nhập)

    Van Rossum không thích cách tiếp cận này lắm vì hàng nhập khẩu xuất hiện ở một nơi xa lạ, nhưng nó hoạt động

    Matthias Urlichs khuyên bạn nên cấu trúc lại mã của mình để không cần nhập đệ quy ngay từ đầu

    Các giải pháp này không loại trừ lẫn nhau

    Thay vào đó, hãy xem xét sử dụng chức năng tiện lợi từ

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    14

    Vì lý do hiệu quả cũng như tính nhất quán, Python chỉ đọc tệp mô-đun trong lần đầu tiên mô-đun được nhập. Nếu không, trong một chương trình bao gồm nhiều mô-đun mà mỗi mô-đun nhập cùng một mô-đun cơ bản, mô-đun cơ bản sẽ được phân tích cú pháp và phân tích lại nhiều lần. Để buộc đọc lại một mô-đun đã thay đổi, hãy làm điều này

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    15

    Cảnh báo. kỹ thuật này không phải là bằng chứng 100%. Cụ thể, các mô-đun chứa các câu lệnh như

    >>> x = 10
    >>> def foo():
    ..     print(x)
    ..     x += 1
    
    16

    sẽ tiếp tục hoạt động với phiên bản cũ của các đối tượng đã nhập. Nếu mô-đun chứa các định nghĩa lớp, các thể hiện của lớp hiện tại sẽ không được cập nhật để sử dụng định nghĩa lớp mới. Điều này có thể dẫn đến hành vi nghịch lý sau đây

    Làm cách nào để sử dụng một giá trị hàm trong một hàm khác trong Python?

    Biến có thể được gán cho đối tượng hàm bên trong thân hàm . Vì vậy, biến chỉ tồn tại sau khi hàm được gọi. Khi hàm đã được gọi, biến sẽ được liên kết với đối tượng hàm.

    Các hàm có thể trả về các hàm khác dưới dạng kết quả trong Python không?

    Hàm trả về một hàm khác trong Python . Đối tượng hạng nhất là một đối tượng có thể được gán cho một biến, được truyền dưới dạng đối số cho hàm hoặc được sử dụng làm giá trị trả về trong hàm. we can return a function from another function. A first-class object is an object that can be assigned to a variable, passed as an argument to a function, or used as a return value in a function.