Python đặt biến toàn cục trong câu lệnh if
Một số trình sửa lỗi cho Python được mô tả bên dưới và chức năng tích hợp sẵn >>> x = 10 >>> def foo(): .. print(x) .. x += 115 cho phép bạn truy cập vào bất kỳ trình gỡ lỗi nào trong số chúng Show
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à >>> x = 10 >>> def foo(): .. print(x) .. x += 116. 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ó công cụ nào giúp tìm lỗi hoặc thực hiện phân tích tĩnh không?¶Đú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 Làm cách nào tôi có thể tạo tệp nhị phân độc lập từ tập lệnh 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
Có các tiêu chuẩn mã hóa hoặc hướng dẫn phong cách cho các chương trình Python không?¶Đú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 Ngôn ngữ cốt lõi¶Tại sao tôi nhận được lỗi UnboundLocalError khi biến có giá trị?¶Có thể ngạc nhiên khi nhận được mã >>> x = 10 >>> def foo(): .. print(x) .. x += 117 trong 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 += 117 >>> 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 += 119, 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 += 120 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 >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 10 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 10 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 121 >>> x = 10 >>> def foo(): .. print(x) .. x += 12 Các quy tắc cho biến cục bộ và biến toàn cục trong Python là gì?¶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, yêu cầu >>> x = 10 >>> def foo(): .. print(x) .. x += 122 cho các biến được chỉ định cung cấp một rào cản đối vớ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 += 122 đượ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 += 122. 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 tuyên bố >>> x = 10 >>> def foo(): .. print(x) .. x += 122 để xác định các tác dụng phụ Tại sao lambdas được xác định trong một vòng lặp với các giá trị khác nhau đều trả về cùng một kết quả?¶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 >>> x = 10 >>> def foo(): .. print(x) .. x += 17 Đ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 += 126. 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 += 127, >>> x = 10 >>> def foo(): .. print(x) .. x += 128, >>> x = 10 >>> def foo(): .. print(x) .. x += 129, >>> x = 10 >>> def foo(): .. print(x) .. x += 130 và >>> x = 10 >>> def foo(): .. print(x) .. x += 131. Tuy nhiên, khi bạn thực sự thử, bạn sẽ thấy rằng tất cả chúng đều quay trở lại >>> x = 10 >>> def foo(): .. print(x) .. x += 131 >>> x = 10 >>> def foo(): .. print(x) .. x += 15 Điều này xảy ra vì >>> x = 10 >>> def foo(): .. print(x) .. x += 119 không phải là cục bộ của lambda, 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 += 119 là >>> x = 10 >>> def foo(): .. print(x) .. x += 129, vì vậy tất cả các hàm bây giờ trả về >>> x = 10 >>> def foo(): .. print(x) .. x += 136, i. e. >>> x = 10 >>> def foo(): .. print(x) .. x += 131. 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 += 119 và xem kết quả của lambdas thay đổi như thế nào >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 102 Để 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 += 119 >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 104 Ở đây, >>> x = 10 >>> def foo(): .. print(x) .. x += 140 tạo một biến mới >>> x = 10 >>> def foo(): .. print(x) .. x += 141 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 += 119 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 += 141 sẽ là >>> x = 10 >>> def foo(): .. print(x) .. x += 127 trong lambda đầu tiên, >>> x = 10 >>> def foo(): .. print(x) .. x += 128 trong lambda thứ hai, >>> x = 10 >>> def foo(): .. print(x) .. x += 146 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 += 10 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 Làm cách nào để chia sẻ các biến toàn cục giữa các mô-đun?¶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 += 11 chế độ. py >>> x = 10 >>> def foo(): .. print(x) .. x += 12 chủ yếu. py >>> x = 10 >>> def foo(): .. print(x) .. x += 13 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ự "Các phương pháp hay nhất" để sử dụng tính năng nhập trong một mô-đun là gì?¶Nói chung, không sử dụng >>> x = 10 >>> def foo(): .. print(x) .. x += 147. 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
Đô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
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 điều đó là cần thiết để giải quyết vấn đề chẳng hạ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ột 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ột 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 vượt ra ngoài phạm vi, thì mô-đun đó vẫn có sẵn trong >>> x = 10 >>> def foo(): .. print(x) .. x += 155 Tại sao các giá trị mặc định được chia sẻ giữa các đối tượng?¶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 += 14 Lần đầu tiên bạn gọi chức năng này, >>> x = 10 >>> def foo(): .. print(x) .. x += 156 chứa một mục duy nhất. Lần thứ hai, >>> x = 10 >>> def foo(): .. print(x) .. x += 156 chứa hai mục bởi vì khi >>> x = 10 >>> def foo(): .. print(x) .. x += 158 bắt đầu thực thi, >>> x = 10 >>> def foo(): .. print(x) .. x += 156 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 += 160 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 += 160 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 += 160 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 += 15 nhưng >>> x = 10 >>> def foo(): .. print(x) .. x += 16 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 += 17 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; Làm cách nào để chuyển các tham số từ khóa hoặc tùy chọn từ hàm này sang hàm khác?¶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 += 163 và >>> x = 10 >>> def foo(): .. print(x) .. x += 164 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 += 163 và >>> x = 10 >>> def foo(): .. print(x) .. x += 164 >>> x = 10 >>> def foo(): .. print(x) .. x += 18 Sự khác biệt giữa đối số và tham số là gì?¶Tham số được xác định bằng tên xuất hiện trong định nghĩa hàm, trong khi đối số là giá trị . Tham số xác định loại đối số mà một hàm có thể chấp nhận. Ví dụ, đưa ra định nghĩa hàm. >>> x = 10 >>> def foo(): .. print(x) .. x += 19 foo, bar và kwargs là các tham số của >>> x = 10 >>> def foo(): .. print(x) .. x += 167. Tuy nhiên, khi gọi >>> x = 10 >>> def foo(): .. print(x) .. x += 167 chẳng hạn >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment0 các giá trị >>> x = 10 >>> def foo(): .. print(x) .. x += 169, >>> x = 10 >>> def foo(): .. print(x) .. x += 170 và >>> x = 10 >>> def foo(): .. print(x) .. x += 171 là các đối số Tại sao thay đổi danh sách 'y' cũng thay đổi danh sách 'x'?¶Nếu bạn đã viết mã như >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment1 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 += 172 lại thay đổi cả >>> x = 10 >>> def foo(): .. print(x) .. x += 119 Có hai yếu tố tạo ra kết quả này
Sau khi gọi đến >>> x = 10 >>> def foo(): .. print(x) .. x += 179, nội dung của đối tượng có thể thay đổi đã thay đổi từ >>> x = 10 >>> def foo(): .. print(x) .. x += 180 thành >>> x = 10 >>> def foo(): .. print(x) .. x += 181. 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 += 181 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 += 119 >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment2 ta thấy trong trường hợp này >>> x = 10 >>> def foo(): .. print(x) .. x += 119 và >>> x = 10 >>> def foo(): .. print(x) .. x += 172 không còn bằng nhau nữa. Điều này là do các số nguyên bất biến và khi chúng tôi thực hiện >>> x = 10 >>> def foo(): .. print(x) .. x += 186, chúng tôi sẽ không thay đổi int >>> x = 10 >>> def foo(): .. print(x) .. x += 187 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 += 188 và >>> x = 10 >>> def foo(): .. print(x) .. x += 187) và hai biến tham chiếu đến chúng ( >>> x = 10 >>> def foo(): .. print(x) .. x += 119 bây giờ tham chiếu đến >>> x = 10 >>> def foo(): .. print(x) .. x += 188 nhưng >>> x = 10 >>> def foo(): .. print(x) .. x += 172 vẫn tham chiếu đến >>> x = 10 >>> def foo(): .. print(x) .. x += 187). Một số thao tác (ví dụ >>> x = 10 >>> def foo(): .. print(x) .. x += 197 và >>> x = 10 >>> def foo(): .. print(x) .. x += 198) làm thay đổi đối tượng, trong khi các thao tác bề ngoài tương tự (ví dụ >>> x = 10 >>> def foo(): .. print(x) .. x += 199 và >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment00) 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 += 160 để 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 198 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 += 172, thì thay vào đó, bạn sẽ kết thúc bằng >>> x = 10 >>> def foo(): .. print(x) .. x += 160, đ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 assignment05 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 assignment06 tương đương với >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment07 và thay đổi >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment08, trong khi >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment09 và >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment10 tạo đối tượng mới) Nói cách khác
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ử >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment17 hoặc hàm có sẵn >>> x = 10 >>> def foo(): .. print(x) .. x += 114 Làm cách nào để viết một hàm có tham số đầu ra (gọi theo tham chiếu)?¶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
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ả Làm thế nào để bạn tạo một hàm bậc cao hơn trong Python?¶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 assignment19 trả về hàm >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment20 tính giá trị >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment21. Sử dụng phạm vi lồng nhau >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment7 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 assignment8 Trong cả hai trường hợp, >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment9 đư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 assignment22 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() 100 Đố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() 101 Ở đây ________ 623, ________ 624 và ________ 625 đóng vai trò như các hàm chia sẻ cùng một biến đếm Làm cách nào để sao chép một đối tượng trong Python?¶Nói chung, hãy thử >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment26 hoặc >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment27 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ó phương thức >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment28 >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 102 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() 103 Làm cách nào tôi có thể tìm thấy các phương thức hoặc thuộc tính của một đối tượng?¶Đối với một thể hiện >>> x = 10 >>> def foo(): .. print(x) .. x += 119 của một lớp do người dùng định nghĩa, >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment30 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ó Làm cách nào mã của tôi có thể khám phá tên của một đối tượng?¶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() 104 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 assignment33, 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 assignment34. 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 assignment35 hay >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment36, vì cả hai tên đều được 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
Điều gì xảy ra với quyền ưu tiên của toán tử dấu phẩy?¶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() 105 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() 106 không phải >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 107 Điều này cũng đúng với các toán tử gán khác nhau ( >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment37, >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment05, 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ó tương đương với C's không?. ” toán tử bậc ba?¶Có, có. Cú pháp như sau >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 108 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() 109 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 assignment39 Có thể viết các dòng một lớp bị xáo trộn bằng Python không?¶Đúng. Thông thường, điều này được thực hiện bằng cách lồng >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment40 vào trong >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment40. Xem ba ví dụ sau, được điều chỉnh một chút từ Ulf Bartelt >>> x = 10 >>> def foo(): .. print(x) .. x += 100 Đừng thử điều này ở nhà, trẻ em Dấu gạch chéo (/) trong danh sách tham số của hàm có nghĩa là gì?¶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ụ, >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment42 là một chức năng chỉ chấp nhận các tham số vị trí. tài liệu của nó trông như thế này >>> x = 10 >>> def foo(): .. print(x) .. x += 101 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 đó, gọi >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment42 với đối số từ khóa sẽ dẫn đến lỗi >>> x = 10 >>> def foo(): .. print(x) .. x += 102 Số và chuỗi¶Làm cách nào để chỉ định số nguyên thập lục phân và bát phân?¶Để 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 103 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 104 Tại sao -22 // 10 lại trả về -3?¶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 assignment44 có cùng dấu hiệu với >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment45. Nếu bạn muốn điều đó, và cũng muốn >>> x = 10 >>> def foo(): .. print(x) .. x += 105 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 assignment46 cần làm cho >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment44 có cùng dấu với >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment48 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 assignment44 khi >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment45 là số âm. Khi >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment45 dương, có rất nhiều và hầu như tất cả chúng đều hữu ích hơn cho >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment44 là >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment53. Nếu bây giờ đồng hồ chỉ 10 giờ thì 200 giờ trước nó chỉ mấy giờ? Làm cách nào để nhận thuộc tính int theo nghĩa đen thay vì SyntaxError?¶Cố gắng tra cứu thuộc tính chữ >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment15 theo cách thông thường sẽ cho kết quả là >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment57 vì dấu chấm được xem là dấu thập phân >>> x = 10 >>> def foo(): .. print(x) .. x += 106 The solution is to separate the literal from the period with either a space or parentheses >>> x = 10 >>> def foo(): .. print(x) .. x += 107 Làm cách nào để chuyển đổi một chuỗi thành một số?¶Đối với số nguyên, hãy sử dụng hàm tạo kiểu >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment58 tích hợp sẵn, e. g. >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment59. Tương tự, >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment60 chuyển thành dấu phẩy động, e. g. >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment61 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 assignment62 đúng và >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment63 tăng >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment64. >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment65 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 assignment66. Nếu cơ sở được chỉ định là 0, số được diễn giải bằng quy tắc của Python. a leading ‘0o’ indicates octal, and ‘0x’ indicates a hex number Do not use the built-in function >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment67 if all you need is to convert strings to numbers. >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment67 will be significantly slower and it presents a security risk. someone could pass you a Python expression that might have unwanted side effects. For example, someone could pass >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment69 which would erase your home directory >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment67 also has the effect of interpreting numbers as Python expressions, so that e. g. >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment71 gives a syntax error because Python does not allow leading ‘0’ in a decimal number (except ‘0’) How do I convert a number to a string?¶Để chuyển đổi, e. g. , the number >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment72 to the string >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment73, use the built-in type constructor >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment74. If you want a hexadecimal or octal representation, use the built-in functions >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment75 or >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment76. For fancy formatting, see the Formatted string literals and Format String Syntax sections, e. g. >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment77 yields >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment78 and >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment79 yields >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment80. How do I modify a string in place?¶You can’t, because strings are immutable. In most situations, you should simply construct a new string from the various parts you want to assemble it from. However, if you need an object with the ability to modify in-place unicode data, try using an >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment81 object or the >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment82 module >>> x = 10 >>> def foo(): .. print(x) .. x += 108 How do I use strings to call functions/methods?¶There are various techniques
Is there an equivalent to Perl’s chomp() for removing trailing newlines from strings?¶You can use >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment86 to remove all occurrences of any line terminator from the end of the string >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment87 without removing other trailing whitespace. If the string >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment87 represents more than one line, with several empty lines at the end, the line terminators for all the blank lines will be removed >>> x = 10 >>> def foo(): .. print(x) .. x += 123 Since this is typically only desired when reading text one line at a time, using >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment89 this way works well Is there a scanf() or sscanf() equivalent?¶Not as such For simple input parsing, the easiest approach is usually to split the line into whitespace-delimited words using the >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment90 method of string objects and then convert decimal strings to numeric values using >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment58 or >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment60. >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment90 supports an optional “sep” parameter which is useful if the line uses something other than whitespace as a separator For more complicated input parsing, regular expressions are more powerful than C’s >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment94 and better suited for the task What does ‘UnicodeDecodeError’ or ‘UnicodeEncodeError’ error mean?¶See the Unicode HOWTO . Performance¶My program is too slow. How do I speed it up?¶That’s a tough one, in general. First, here are a list of things to remember before diving further
Đ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
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 tự tin vào kỹ năng lập trình C của mình, bạn cũng có thể viết mô-đun mở rộng C cho mình. Xem thêm Trang wiki dành cho mẹo hiệu suất Cách hiệu quả nhất để nối nhiều chuỗi lại với nhau là gì?¶Các đối tượng >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment14 và >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1001 là bất biến, do đó việc nối nhiều chuỗi lại với nhau sẽ 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 >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment14, thành ngữ được đề xuất là đặt chúng vào một danh sách và gọi >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1003 ở cuối >>> x = 10 >>> def foo(): .. print(x) .. x += 124 (một thành ngữ hiệu quả hợp lý khác là sử dụng >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment81) Để tích lũy nhiều đối tượng >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1001, thành ngữ được khuyến nghị là mở rộng đối tượng >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1006 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 assignment05) >>> x = 10 >>> def foo(): .. print(x) .. x += 125 Trình tự (Bộ dữ liệu/Danh sách)¶Làm cách nào để chuyển đổi giữa các bộ dữ liệu và danh sách?¶Hàm tạo kiểu >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1008 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() 1009 mang lại >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1010 và >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1011 mang lại >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1012. 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 khi gọi >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1013 khi 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() 1014 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 các mục theo cùng một thứ tự. Ví dụ: >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1015 mang lại >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1016 và >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1017 mang lại >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1018. 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() 1019 Chỉ số âm là gì?¶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() 1020 giống như >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1021 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() 1022 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 Làm cách nào để lặp lại một chuỗi theo thứ tự ngược lại?¶Sử dụng chức năng tích hợp sẵn >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1023 >>> x = 10 >>> def foo(): .. print(x) .. x += 126 Đ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 Làm cách nào để loại bỏ các mục trùng lặp khỏi danh sách?¶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
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 >>> x = 10 >>> def foo(): .. print(x) .. x += 127 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. tất cả chúng đều có thể băm ), điều này thường nhanh hơn >>> x = 10 >>> def foo(): .. print(x) .. x += 128 Đ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 Làm cách nào để xóa nhiều mục khỏ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 hơn 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ể >>> x = 10 >>> def foo(): .. print(x) .. x += 129 Việc hiểu danh sách có thể nhanh nhất Làm thế nào để bạn tạo một mảng trong Python?¶Sử dụng một danh sách >>> x = 10 >>> def foo(): .. print(x) .. x += 170 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 assignment82 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 171 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() 1025 và dạng tương tự của cdr là >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1026. 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 Làm cách nào để tạo danh sách đa chiều?¶Có thể bạn đã thử tạo một mảng nhiều chiều như thế này >>> x = 10 >>> def foo(): .. print(x) .. x += 172 Điều này có vẻ đúng nếu bạn in nó >>> x = 10 >>> def foo(): .. print(x) .. x += 173 Nhưng khi bạn chỉ định một giá trị, nó sẽ hiển thị ở nhiều nơi >>> x = 10 >>> def foo(): .. print(x) .. x += 174 Lý do là việc sao chép danh sách bằng >>> x = 10 >>> def foo(): .. print(x) .. x += 163 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() 1028 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 foo(): .. print(x) .. x += 175 Đ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 foo(): .. print(x) .. x += 176 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; Làm cách nào để áp dụng một phương thức hoặc hàm cho một chuỗi các đối tượng?¶Để 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, việc hiểu danh sách là một giải pháp tinh tế. >>> x = 10 >>> def foo(): .. print(x) .. x += 177 Để 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 >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1029 đơn giản là đủ >>> x = 10 >>> def foo(): .. print(x) .. x += 178 Tại sao a_tuple[i] += [‘item’] đưa ra một ngoại lệ khi phép cộng hoạt động?¶Đ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 assignment11 và >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment05 làm ví dụ của chúng tôi Nếu bạn đã viết >>> x = 10 >>> def foo(): .. print(x) .. x += 179 Lý do ngoại lệ phải rõ ràng ngay lập tức. >>> x = 10 >>> def foo(): .. print(x) .. x += 128 được thêm vào đối tượng >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1033 trỏ tới ( >>> x = 10 >>> def foo(): .. print(x) .. x += 128), tạo ra đối tượng kết quả, >>> x = 10 >>> def foo(): .. print(x) .. x += 146, 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 += 146, cho phần tử >>> x = 10 >>> def foo(): .. print(x) .. x += 127 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 foo(): .. print(x) .. x += 150 Đó 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 foo(): .. print(x) .. x += 151 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 foo(): .. print(x) .. x += 152 Để biết tại sao điều này lại 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 >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1038, 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 assignment05 đượ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 assignment05 là “viết tắt” của >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1043 >>> x = 10 >>> def foo(): .. print(x) .. x += 153 Điều này tương đương với >>> x = 10 >>> def foo(): .. print(x) .. x += 154 Đố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 assignment08. 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 assignment08 đã 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 foo(): .. print(x) .. x += 155 >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1038 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() 1047 trỏ đến cùng một đối tượng mà >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1033 đã 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 Tôi muốn làm một sắp xếp phức tạp. bạn có thể thực hiện Biến đổi Schwartzian bằng Python không?¶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() 1049 cho phương thức >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment98 >>> x = 10 >>> def foo(): .. print(x) .. x += 156 Làm cách nào tôi có thể sắp xếp một danh sách theo các giá trị từ một danh sách khác?¶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 foo(): .. print(x) .. x += 157 Các đối tượng¶Lớp học là gì?¶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() 1051 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() 1052, >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1053, >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1054 xử lý các định dạng hộp thư cụ thể khác nhau Phương pháp là gì?¶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 += 119 mà bạn thường gọi là >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1056. 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 foo(): .. print(x) .. x += 158 Bản ngã là gì?¶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à >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1057 nên được gọi là >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1058 đối với một số trường hợp >>> x = 10 >>> def foo(): .. print(x) .. x += 119 của lớp mà định nghĩa xảy ra; Xem thêm Tại sao phải sử dụng 'self' một cách rõ ràng trong các định nghĩa và lệnh gọi phương thức? . Làm cách nào để kiểm tra xem một đối tượng là một thể hiện của một lớp đã cho hay một lớp con của nó?¶Sử dụng chức năng tích hợp sẵn >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1061. 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() 1062 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() 1063 hoặc >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1064 Lưu ý rằng >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1065 cũng kiểm tra tính kế thừa ảo từ một lớp cơ sở trừu tượng . Vì vậy, bài kiểm tra sẽ trả về >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1066 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 "kế thừa thực sự", hãy quét MRO của lớp. >>> x = 10 >>> def foo(): .. print(x) .. x += 159 >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1020 Lưu ý rằng hầu hết các chương trình không thường xuyên sử dụng >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1065 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() 1021 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() 1068 trên tất cả các lớp và chỉ cần gọi nó là >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1022 Ủy quyền là gì?¶Ủ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 += 119 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 += 119 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() 1023 Ở đây, lớp >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1071 định nghĩa lại phương thức >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1072 để 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() 1073 bên dưới. All other methods are delegated to the underlying >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1074 object. The delegation is accomplished via the >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1075 method; consult the language reference for more information about controlling attribute access. Note that for more general cases delegation can get trickier. When attributes must be set as well as retrieved, the class must define a >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1076 method too, and it must do so carefully. The basic implementation of >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1076 is roughly equivalent to the following >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1024 Most >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1076 implementations must modify >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1079 to store local state for self without causing an infinite recursion How do I call a method defined in a base class from a derived class that extends it?¶Use the built-in >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1080 function >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1025 In the example, >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1080 will automatically determine the instance from which it was called (the >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1082 value), look up the method resolution order (MRO) with >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1083, and return the next in line after >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1084 in the MRO. >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1085. How can I organize my code to make it easier to change the base class?¶You could assign the base class to an alias and derive from the alias. Then all you have to change is the value assigned to the alias. Incidentally, this trick is also handy if you want to decide dynamically (e. g. depending on availability of resources) which base class to use. Example >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1026 How do I create static class data and static class methods?¶Both static data and static methods (in the sense of C++ or Java) are supported in Python For static data, simply define a class attribute. To assign a new value to the attribute, you have to explicitly use the class name in the assignment >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1027 >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1086 also refers to >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1087 for any >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1088 such that >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1089 holds, unless overridden by >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1088 itself or by some class on the base-class search path from >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1091 back to >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1092 Caution. within a method of C, an assignment like >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1093 creates a new and unrelated instance named “count” in >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1082’s own dict. Rebinding of a class-static data name must always specify the class whether inside a method or not >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1028 Static methods are possible >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1029 However, a far more straightforward way to get the effect of a static method is via a simple module-level function >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1040 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 How can I overload constructors (or methods) in Python?¶This answer actually applies to all methods, but the question usually comes up first in the context of constructors In C++ you’d write >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1041 In Python you have to write a single constructor that catches all cases using default arguments. For example >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1042 This is not entirely equivalent, but close enough in practice You could also try a variable-length argument list, e. g >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1043 The same approach works for all method definitions I try to use __spam and I get an error about _SomeClassName__spam. ¶Variable names with double leading underscores are “mangled” to provide a simple but effective way to define class private variables. Any identifier of the form >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1095 (at least two leading underscores, at most one trailing underscore) is textually replaced with >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1096, where >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1097 is the current class name with any leading underscores stripped This doesn’t guarantee privacy. an outside user can still deliberately access the “_classname__spam” attribute, and private values are visible in the object’s >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1098. Many Python programmers never bother to use private variable names at all My class defines __del__ but it is not called when I delete the object. ¶There are several possible reasons for this The >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1099 statement does not necessarily call >>> x = 10 >>> def foo(): .. print(x) .. x += 1000 – it simply decrements the object’s reference count, and if this reaches zero >>> x = 10 >>> def foo(): .. print(x) .. x += 1000 is called 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. a tree where each child has a parent reference and each parent has a list of children) the reference counts will never go back to zero. Once in a while Python runs an algorithm to detect such cycles, but the garbage collector might run some time after the last reference to your data structure vanishes, so your >>> x = 10 >>> def foo(): .. print(x) .. x += 1000 method may be called at an inconvenient and random time. This is inconvenient if you’re trying to reproduce a problem. Worse, the order in which object’s >>> x = 10 >>> def foo(): .. print(x) .. x += 1000 methods are executed is arbitrary. You can run >>> x = 10 >>> def foo(): .. print(x) .. x += 1004 to force a collection, but there are pathological cases where objects will never be collected Despite the cycle collector, it’s still a good idea to define an explicit >>> x = 10 >>> def foo(): .. print(x) .. x += 1005 method on objects to be called whenever you’re done with them. The >>> x = 10 >>> def foo(): .. print(x) .. x += 1005 method can then remove attributes that refer to subobjects. Don’t call >>> x = 10 >>> def foo(): .. print(x) .. x += 1000 directly – >>> x = 10 >>> def foo(): .. print(x) .. x += 1000 should call >>> x = 10 >>> def foo(): .. print(x) .. x += 1005 and >>> x = 10 >>> def foo(): .. print(x) .. x += 1005 should make sure that it can be called more than once for the same object Another way to avoid cyclical references is to use the >>> x = 10 >>> def foo(): .. print(x) .. x += 1011 module, which allows you to point to objects without incrementing their reference count. 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. ) Finally, if your >>> x = 10 >>> def foo(): .. print(x) .. x += 1000 method raises an exception, a warning message is printed to >>> x = 10 >>> def foo(): .. print(x) .. x += 1013 Làm cách nào để tôi có được danh sách tất cả các phiên bản của một lớp nhất định?¶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). You can program the class’s constructor to keep track of all instances by keeping a list of weak references to each instance Why does the result of >>> x = 10 >>> def foo(): .. print(x) .. x += 1 14 appear to be not unique?¶The >>> x = 10 >>> def foo(): .. print(x) .. x += 114 builtin returns an integer that is guaranteed to be unique during the lifetime of the object. 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ớ. This is illustrated by this example >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1044 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 += 114. Để 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 bar(): .. print(x) ... >>> bar() 1045 Khi nào tôi có thể dựa vào kiểm tra nhận dạng với toán tử is?¶Toán tử >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment17 kiểm tra danh tính đối tượng. Bài kiểm tra >>> x = 10 >>> def foo(): .. print(x) .. x += 1018 tương đương với >>> x = 10 >>> def foo(): .. print(x) .. x += 1019 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ó, >>> x = 10 >>> def foo(): .. print(x) .. x += 1020 luôn trả về >>> x = 10 >>> def foobar(): .. global x .. print(x) .. x += 1 ... >>> foobar() 1066. 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() 1066 hoặc >>> x = 10 >>> def foo(): .. print(x) .. x += 1023 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1024, đảm bảo rằng >>> x = 10 >>> def foo(): .. print(x) .. x += 1025 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1026, đảm bảo rằng >>> x = 10 >>> def foo(): .. print(x) .. x += 1027 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 phép gán >>> x = 10 >>> def foo(): .. print(x) .. x += 1028 và >>> x = 10 >>> def foo(): .. print(x) .. x += 1029, đảm bảo rằng >>> x = 10 >>> def foo(): .. print(x) .. x += 1018 vì >>> x = 10 >>> def foo(): .. print(x) .. x += 160 là một đơn vị 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ư >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment15 và >>> foo() Traceback (most recent call last): ... UnboundLocalError: local variable 'x' referenced before assignment14 không được đảm bảo là đơn lẻ >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1046 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 bar(): .. print(x) ... >>> bar() 1047 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 += 160. Đ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 += 160 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 += 1036 >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1048 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ư >>> x = 10 >>> def foo(): .. print(x) .. x += 1037 không bằng chính chúng Ví dụ: đây là triển khai của >>> x = 10 >>> def foo(): .. print(x) .. x += 1038 >>> x = 10 >>> def bar(): .. print(x) ... >>> bar() 1049 Làm thế nào một lớp con có thể kiểm soát dữ liệu nào được lưu trữ trong một thể hiện không thay đổi?¶Khi phân lớp một loại bất biến, hãy ghi đè phương thức >>> x = 10 >>> def foo(): .. print(x) .. x += 1039 thay vì phương thức >>> x = 10 >>> def foo(): .. print(x) .. x += 1040. 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 += 100 Các lớp có thể được sử dụng như thế này >>> x = 10 >>> def foo(): .. print(x) .. x += 101 Làm cách nào để lưu trữ các lệnh gọi phương thức?¶Hai công cụ chính cho các phương pháp lưu vào bộ nhớ đệm là >>> x = 10 >>> def foo(): .. print(x) .. x += 1041 và >>> x = 10 >>> def foo(): .. print(x) .. x += 1042. 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 += 102 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1043 và >>> x = 10 >>> def foo(): .. print(x) .. x += 1044 để 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 += 103 Mô-đun¶Làm cách nào để tạo một. tập tin pyc?¶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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 chứa mã đã biên dịch sẽ được tạo trong thư mục con >>> x = 10 >>> def foo(): .. print(x) .. x += 1046 của thư mục chứa tệp >>> x = 10 >>> def foo(): .. print(x) .. x += 1047. Tệp >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 sẽ có tên tệp bắt đầu bằng tên giống như tệp >>> x = 10 >>> def foo(): .. print(x) .. x += 1047 và kết thúc bằng >>> x = 10 >>> def foo(): .. print(x) .. x += 1045, với thành phần ở giữa phụ thuộc vào mã nhị phân cụ thể của >>> x = 10 >>> def foo(): .. print(x) .. x += 1051 đã tạo ra nó. (Xem PEP 3147 để biết chi tiết. ) Một lý do khiến tệp >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1046. Điều này có thể xảy ra, ví dụ: 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1054 đượ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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1046 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ó >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 nào được tạo. Ví dụ: nếu bạn có mô-đun cấp cao nhất >>> x = 10 >>> def foo(): .. print(x) .. x += 1057 nhập mô-đun khác >>> x = 10 >>> def foo(): .. print(x) .. x += 1058, khi bạn chạy >>> x = 10 >>> def foo(): .. print(x) .. x += 1059 (bằng cách nhập >>> x = 10 >>> def foo(): .. print(x) .. x += 1060 dưới dạng lệnh trình bao), một >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 sẽ được tạo cho >>> x = 10 >>> def foo(): .. print(x) .. x += 1062 vì >>> x = 10 >>> def foo(): .. print(x) .. x += 1062 được nhập, nhưng sẽ không có tệp >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 nào được nhập Nếu bạn cần tạo tệp >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 cho >>> x = 10 >>> def foo(): .. print(x) .. x += 1059 – nghĩa là tạo tệp >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 cho mô-đun không được nhập – bạn có thể, bằng cách sử dụng mô-đun >>> x = 10 >>> def foo(): .. print(x) .. x += 1070 và >>> x = 10 >>> def foo(): .. print(x) .. x += 1071 Mô-đun >>> x = 10 >>> def foo(): .. print(x) .. x += 1070 có thể biên dịch thủ công bất kỳ mô-đun nào. Một cách là sử dụng chức năng >>> x = 10 >>> def foo(): .. print(x) .. x += 1073 trong mô-đun đó một cách tương tác >>> x = 10 >>> def foo(): .. print(x) .. x += 104 Thao tác này sẽ ghi >>> x = 10 >>> def foo(): .. print(x) .. x += 1045 vào thư mục con >>> x = 10 >>> def foo(): .. print(x) .. x += 1046 ở cùng vị trí với >>> x = 10 >>> def foo(): .. print(x) .. x += 1057 (hoặc bạn có thể ghi đè lên thư mục đó bằng tham số tùy chọn >>> x = 10 >>> def foo(): .. print(x) .. x += 1077) 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 các thư mục bằng cách sử dụng mô-đun >>> x = 10 >>> def foo(): .. print(x) .. x += 1071. Bạn có thể làm điều đó từ dấu nhắc shell bằng cách chạy >>> x = 10 >>> def foo(): .. print(x) .. x += 1079 và cung cấp đường dẫn của một thư mục chứa các tệp Python để biên dịch >>> x = 10 >>> def foo(): .. print(x) .. x += 105 Làm cách nào để tìm tên mô-đun hiện tại?¶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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1080. Nếu giá trị này có giá trị >>> x = 10 >>> def foo(): .. print(x) .. x += 1081, 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1080 >>> x = 10 >>> def foo(): .. print(x) .. x += 106 Làm cách nào tôi có thể có các mô-đun nhập lẫn nhau?¶Giả sử bạn có các mô-đun sau >>> x = 10 >>> def foo(): .. print(x) .. x += 1057 >>> x = 10 >>> def foo(): .. print(x) .. x += 107 >>> x = 10 >>> def foo(): .. print(x) .. x += 1084 >>> x = 10 >>> def foo(): .. print(x) .. x += 108 Vấn đề là trình thông dịch sẽ thực hiện các bước sau
Bước cuối cùng không thành công, vì Python vẫn chưa hoàn thành việc phiên dịch >>> x = 10 >>> def foo(): .. print(x) .. x += 1059 và từ điển ký hiệu chung cho >>> x = 10 >>> def foo(): .. print(x) .. x += 1059 vẫn còn trống Điều tương tự cũng xảy ra khi bạn sử dụng >>> x = 10 >>> def foo(): .. print(x) .. x += 1200, sau đó thử truy cập >>> x = 10 >>> def foo(): .. print(x) .. x += 1201 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 >>> x = 10 >>> def foo(): .. print(x) .. x += 1202 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à >>> x = 10 >>> def foo(): .. print(x) .. x += 1203 Jim Roskind gợi ý thực hiện các bước theo thứ tự sau trong mỗi mô-đun
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 __import__(‘x.y.z’) returns ; how do I get z?¶Thay vào đó, hãy cân nhắc sử dụng chức năng tiện lợi >>> x = 10 >>> def foo(): .. print(x) .. x += 1205 từ >>> x = 10 >>> def foo(): .. print(x) .. x += 1206 >>> x = 10 >>> def foo(): .. print(x) .. x += 109 Khi tôi chỉnh sửa một mô-đun đã nhập và nhập lại mô-đun đó, các thay đổi không hiển thị. Lý do tại sao điều này xảy ra?¶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 += 110 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 += 111 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 có 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 Tôi có thể định nghĩa một biến toàn cục bên trong một hàm trong Python không?Mọi người đều có thể sử dụng biến toàn cục, cả bên trong và bên ngoài hàm .
Bạn có thể khai báo một biến trong câu lệnh if Python không?python cho phép tạo các biến trong if. elif. khác. mệnh đề , để chúng cũng có thể được sử dụng bên ngoài khối điều kiện. Điều này cũng đúng với các điều kiện lồng nhau.
Biến trong câu lệnh if có phải là toàn cục không?Lại. Sử dụng biến toàn cục trong hàm với câu lệnh if
. Tất cả các biến được khai báo trong không gian tên (toàn cục) đầu tiên đều là toàn cục . Tất cả các biến khác (được khai báo trong một hàm) là cục bộ trong hàm.
Làm cách nào bạn có thể truy cập một biến toàn cục bên trong hàm nếu hàm có một biến có cùng tên?Để truy cập biến toàn cục trong hàm, nếu hàm đó có biến cục bộ trùng tên, chúng ta dùng từ khóa toàn cục trước tên biến. |