Quy tắc lập trình python
Trong Python, bạn sử dụng từ khóa 44 để tạo mã trong một mô-đun có sẵn trong một mô-đun khác. Nhập trong Python rất quan trọng để cấu trúc mã của bạn một cách hiệu quả. Sử dụng nhập đúng cách sẽ giúp bạn làm việc hiệu quả hơn, cho phép bạn sử dụng lại mã trong khi vẫn duy trì dự án của mình Show
Hướng dẫn này sẽ cung cấp một cái nhìn tổng quan về câu lệnh 44 của Python và cách thức hoạt động của nó. Hệ thống nhập rất mạnh và bạn sẽ học cách khai thác sức mạnh này. Mặc dù bạn sẽ đề cập đến nhiều khái niệm đằng sau hệ thống nhập của Python, hướng dẫn này chủ yếu dựa trên ví dụ. Bạn sẽ học được từ một số ví dụ mã trong suốtTrong hướng dẫn này, bạn sẽ học cách
Xuyên suốt hướng dẫn, bạn sẽ thấy các ví dụ về cách chơi với bộ máy nhập Python để hoạt động hiệu quả nhất. Mặc dù tất cả mã được hiển thị trong hướng dẫn, nhưng bạn cũng có thể tải xuống bằng cách nhấp vào hộp bên dưới Lấy mã nguồn. Nhấp vào đây để lấy mã nguồn mà bạn sẽ sử dụng để tìm hiểu về hệ thống nhập Python trong hướng dẫn này Python cơ bản >>> import math >>> dir() ['__annotations__', '__builtins__', ..., 'math'] >>> dir(math) ['__doc__', ..., 'nan', 'pi', 'pow', ...] 44Mã Python được tổ chức thành cả mô-đun và gói. Phần này sẽ giải thích chúng khác nhau như thế nào và bạn có thể làm việc với chúng như thế nào Ở phần sau của hướng dẫn, bạn sẽ thấy một số cách sử dụng nâng cao và ít được biết đến của hệ thống nhập của Python. Tuy nhiên, hãy bắt đầu với những điều cơ bản. nhập mô-đun và gói Loại bỏ các quảng cáomô-đuncon trăn. thuật ngữ org định nghĩa mô-đun như sau
Trong thực tế, một mô-đun thường tương ứng với một tệp 47 chứa mã PythonSức mạnh thực sự của các mô-đun là chúng có thể được nhập và sử dụng lại trong mã khác. Xem xét ví dụ sau >>>
Trong dòng đầu tiên, 48, bạn nhập mã trong mô-đun 49 và cung cấp mã đó để sử dụng. Ở dòng thứ hai, bạn truy cập biến 50 trong mô-đun 49. 49 là một phần của thư viện chuẩn của Python, có nghĩa là nó luôn có sẵn để nhập khi bạn chạy PythonLưu ý rằng bạn viết 53 và không chỉ đơn giản là 50. Ngoài vai trò là một mô-đun, 49 hoạt động như một không gian tên giữ tất cả các thuộc tính của mô-đun lại với nhau. Không gian tên rất hữu ích để giữ cho mã của bạn dễ đọc và có tổ chức. Theo lời của Tim Peters
Bạn có thể liệt kê nội dung của một không gian tên với 56>>>
Sử dụng 56 mà không có bất kỳ đối số nào sẽ hiển thị những gì trong không gian tên chung. Để xem nội dung của không gian tên 49, bạn sử dụng 59Bạn đã thấy cách sử dụng đơn giản nhất của 44. Tuy nhiên, có nhiều cách khác để sử dụng nó cho phép bạn nhập các phần cụ thể của mô-đun và đổi tên mô-đun khi bạn nhập mô-đun đóĐoạn mã sau chỉ nhập biến 50 từ mô-đun 49>>> 1Lưu ý rằng nơi này đặt 50 trong không gian tên chung chứ không phải trong không gian tên 49Bạn cũng có thể đổi tên các mô-đun và thuộc tính khi chúng được nhập >>> 4Để biết thêm chi tiết về cú pháp nhập mô-đun, hãy xem Mô-đun và Gói Python – Giới thiệu góiBạn có thể sử dụng một gói để tổ chức thêm các mô-đun của mình. con trăn. thuật ngữ org định nghĩa gói như sau
Lưu ý rằng một gói vẫn là một mô-đun. Là người dùng, bạn thường không cần phải lo lắng về việc bạn đang nhập mô-đun hay gói Trong thực tế, một gói thường tương ứng với một thư mục tệp chứa các tệp Python và các thư mục khác. Để tự tạo một gói Python, bạn tạo một thư mục và một tệp có tên 66 bên trong nó. Tệp 66 chứa nội dung của gói khi được coi là mô-đun. Nó có thể để trốngGhi chú. Các thư mục không có tệp 66 vẫn được Python coi là gói. Tuy nhiên, đây sẽ không phải là các gói thông thường, mà là một thứ gọi là gói không gian tên. Bạn sẽ tìm hiểu thêm về chúng sauNói chung, các mô-đun con và gói con không được nhập khi bạn nhập một gói. Tuy nhiên, bạn có thể sử dụng 66 để bao gồm bất kỳ hoặc tất cả các mô hình con và gói con nếu bạn muốn. Để hiển thị một vài ví dụ về hành vi này, bạn sẽ tạo một gói để nói 70 bằng một vài ngôn ngữ khác nhau. Gói này sẽ bao gồm các thư mục và tệp sau 1Mỗi tệp quốc gia in ra một lời chào, trong khi tệp 66 nhập có chọn lọc một số gói con và mô hình con. Nội dung chính xác của các tập tin như sau 3Lưu ý rằng 72 chỉ nhập khẩu 73 chứ không phải 74. Tương tự, 75 không nhập bất cứ thứ gì, trong khi 76 nhập 77 và 78 nhưng không nhập 79. Mỗi mô-đun quốc gia sẽ in lời chào khi được nhậpHãy chơi với gói 80 tại dấu nhắc tương tác để hiểu rõ hơn về cách hoạt động của các gói con và mô-đun con>>> 3Khi 74 được nhập, các mô-đun 82 và 83 cũng được nhập. Bạn có thể thấy điều này vì các mô-đun quốc gia in lời chào khi chúng được nhập>>> 7Tệp 75 trống. Điều này có nghĩa là việc nhập gói 85 sẽ tạo không gian tên nhưng không có tác dụng nào khác>>> 0Hãy nhớ rằng, nhập một mô-đun vừa tải nội dung vừa tạo một không gian tên chứa nội dung. Một vài ví dụ cuối cùng cho thấy rằng cùng một mô-đun có thể là một phần của các không gian tên khác nhau Chi tiết kỹ thuật. Không gian tên mô-đun được triển khai dưới dạng từ điển Python và có sẵn tại thuộc tính 86>>> 2Bạn hiếm khi cần tương tác trực tiếp với 86Tương tự, không gian tên toàn cục của Python cũng là một từ điển. Bạn có thể truy cập nó thông qua 88Việc nhập các gói con và mô-đun con trong tệp 66 là khá phổ biến để cung cấp chúng dễ dàng hơn cho người dùng của bạn. Bạn có thể xem một ví dụ về điều này trong gói 90 phổ biếnLoại bỏ các quảng cáoNhập khẩu tuyệt đối và tương đốiNhớ lại mã nguồn của 72 trong ví dụ trước 0Bạn đã từng thấy các câu lệnh của 92 chẳng hạn như 93, nhưng dấu chấm ( 94) trong 95 có nghĩa là gì?Dấu chấm đề cập đến gói hiện tại và câu lệnh là một ví dụ về nhập tương đối. Bạn có thể đọc nó là “Từ gói hiện tại, nhập gói phụ 73. ”Có một câu lệnh nhập tuyệt đối tương đương trong đó bạn đặt tên rõ ràng cho gói hiện tại 1Trên thực tế, tất cả các lần nhập trong 80 có thể đã được thực hiện rõ ràng với các lần nhập tuyệt đối tương tựNhập tương đối phải ở dạng 92 và vị trí bạn đang nhập phải bắt đầu bằng dấu chấmHướng dẫn kiểu PEP 8 khuyến nghị sử dụng nhập khẩu tuyệt đối nói chung. Tuy nhiên, nhập khẩu tương đối là một giải pháp thay thế để tổ chức phân cấp gói. Để biết thêm thông tin, hãy xem Nhập tuyệt đối và tương đối trong Python Đường dẫn nhập của PythonLàm cách nào để Python tìm thấy các mô-đun và gói mà nó nhập? . Hiện tại, chỉ cần biết rằng Python tìm kiếm các mô-đun và gói trong đường dẫn nhập của nó. Đây là danh sách các vị trí được tìm kiếm các mô-đun để nhập Ghi chú. Khi bạn nhập 99, Python sẽ tìm kiếm 100 ở một số vị trí khác nhau trước khi tìm kiếm đường dẫn nhậpCụ thể, nó sẽ tìm kiếm trong bộ đệm mô-đun để xem liệu 100 đã được nhập chưa và nó sẽ tìm kiếm trong số các mô-đun tích hợpBạn sẽ tìm hiểu thêm về bộ máy nhập Python đầy đủ trong phần sau Bạn có thể kiểm tra đường dẫn nhập của Python bằng cách in 102. Nói chung, danh sách này sẽ chứa ba loại địa điểm khác nhau
Thông thường, Python sẽ bắt đầu ở đầu danh sách các vị trí và tìm kiếm một mô-đun nhất định ở mỗi vị trí cho đến khi khớp đầu tiên. Vì thư mục tập lệnh hoặc thư mục hiện tại luôn ở vị trí đầu tiên trong danh sách này, nên bạn có thể đảm bảo rằng các tập lệnh của mình tìm thấy các mô-đun và gói tự tạo bằng cách tổ chức các thư mục của bạn và cẩn thận về việc bạn chạy Python từ thư mục nào Tuy nhiên, bạn cũng nên cẩn thận rằng bạn không tạo các mô-đun che khuất hoặc ẩn các mô-đun quan trọng khác. Ví dụ, giả sử bạn xác định mô-đun 49 sau 2Sử dụng mô-đun này hoạt động như mong đợi >>> 3Nhưng mô-đun này cũng phủ bóng mô-đun 49 có trong thư viện chuẩn. Thật không may, điều đó có nghĩa là ví dụ tra cứu giá trị của π trước đây của chúng tôi không còn hoạt động nữa>>> 4Vấn đề là Python hiện tìm kiếm mô-đun 49 mới của bạn cho 50 thay vì tìm kiếm mô-đun 49 trong thư viện chuẩnĐể tránh những loại sự cố này, bạn nên cẩn thận với tên của các mô-đun và gói của mình. Cụ thể, tên gói và mô-đun cấp cao nhất của bạn phải là duy nhất. Nếu 49 được định nghĩa là một mô-đun con trong một gói, thì nó sẽ không che khuất mô-đun tích hợpLoại bỏ các quảng cáoVí dụ. Cấu trúc nhập khẩu của bạnMặc dù có thể tổ chức quá trình nhập của bạn bằng cách sử dụng thư mục hiện tại cũng như bằng cách thao tác với 103 và thậm chí là 102, quá trình này thường không theo quy tắc và dễ xảy ra lỗi. Để xem một ví dụ điển hình, hãy xem xét ứng dụng sau 5Ứng dụng sẽ tạo lại cấu trúc tệp đã cho bằng cách tạo thư mục và tệp trống. Tệp 112 chứa tập lệnh chính và 113 là mô-đun thư viện có một số chức năng để xử lý tệp. Sau đây là một ví dụ về đầu ra từ ứng dụng, trong trường hợp này bằng cách chạy nó trong thư mục 114 6Hai tệp mã nguồn cũng như tệp 115 được tạo tự động được tạo lại bên trong một thư mục mới có tên là 116Bây giờ hãy xem mã nguồn. Chức năng chính của ứng dụng được xác định trong 112 7Trong các dòng 12 đến 16, bạn đọc đường dẫn gốc từ dòng lệnh. Trong ví dụ trên bạn sử dụng dấu chấm, có nghĩa là thư mục hiện tại. Đường dẫn này sẽ được sử dụng làm 118 của hệ thống phân cấp tệp mà bạn sẽ tạo lạiCông việc thực tế xảy ra ở dòng 19 đến 23. Trước tiên, bạn tạo một đường dẫn duy nhất, 119, đây sẽ là gốc của hệ thống phân cấp tệp mới của bạn. Sau đó, bạn lặp qua tất cả các đường dẫn bên dưới bản gốc 118 và tạo lại chúng dưới dạng các tệp trống bên trong hệ thống phân cấp tệp mớiĐể thao tác với các đường dẫn như thế này, 121 trong thư viện tiêu chuẩn khá hữu ích. Để biết thêm chi tiết về cách nó được sử dụng, hãy xem Mô-đun 121 của Python 3. Thuần hóa hệ thống tập tinTrên dòng 26, bạn gọi 123. Bạn sẽ tìm hiểu thêm về bài kiểm tra 124 ở dòng 25 sau. Bây giờ, bạn nên biết rằng biến đặc biệt 125 có giá trị 126 bên trong các tập lệnh, nhưng nó lấy tên của mô-đun bên trong các mô-đun đã nhập. Để biết thêm thông tin về 125, hãy xem Xác định hàm chính trong Python và Điều gì sẽ xảy ra nếu tên == “chính” Làm trong Python?Lưu ý rằng bạn nhập 128 trên dòng 8. Mô-đun thư viện này chứa hai chức năng tiện ích 8 129 sử dụng bộ đếm để tìm đường dẫn chưa tồn tại. Trong ứng dụng, bạn sử dụng nó để tìm một thư mục con duy nhất để sử dụng làm 119 của hệ thống phân cấp tệp được tạo lại. Tiếp theo, 131 đảm bảo rằng tất cả các thư mục cần thiết đã được tạo trước khi tạo một tệp trống bằng cách sử dụng 132Hãy xem lại việc nhập 128 9Nó trông khá ngây thơ. Tuy nhiên, khi dự án phát triển, dòng này sẽ khiến bạn đau đầu. Mặc dù bạn nhập 128 từ dự án 114, việc nhập là tuyệt đối. nó không bắt đầu bằng dấu chấm. Điều này có nghĩa là phải tìm thấy 128 trong đường dẫn nhập để quá trình nhập hoạt độngMay mắn thay, thư mục chứa tập lệnh hiện tại luôn nằm trong đường dẫn nhập của Python, vì vậy hiện tại nó hoạt động tốt. Tuy nhiên, nếu dự án của bạn đạt được một số lực kéo, thì nó có thể được sử dụng theo những cách khác Ví dụ: ai đó có thể muốn nhập tập lệnh vào Jupyter Notebook và chạy tập lệnh từ đó. Hoặc họ có thể muốn sử dụng lại thư viện 128 trong một dự án khác. Họ thậm chí có thể tạo một tệp thực thi bằng PyInstaller để phân phối dễ dàng hơn. Thật không may, bất kỳ tình huống nào trong số này đều có thể tạo ra sự cố khi nhập 128Để xem ví dụ, bạn có thể làm theo hướng dẫn PyInstaller và tạo một điểm vào cho ứng dụng của mình. Thêm một thư mục bổ sung bên ngoài thư mục ứng dụng của bạn 10Trong thư mục bên ngoài, tạo tập lệnh điểm vào, 139 11Tập lệnh này sẽ nhập 123 từ tập lệnh gốc của bạn và chạy nó. Lưu ý rằng 123 không chạy khi 114 được nhập vì thử nghiệm 124 trên dòng 25 trong 112. Điều đó có nghĩa là bạn cần chạy 123 một cách rõ ràngVề lý thuyết, điều này sẽ hoạt động tương tự như chạy ứng dụng trực tiếp 12Tại sao nó không hoạt động? Vấn đề là khi khởi động ứng dụng bằng 139, bạn đã thay đổi vị trí của tập lệnh hiện tại, do đó thay đổi đường dẫn nhập. 128 không còn trên đường dẫn nhập, vì vậy không thể nhập hoàn toànMột giải pháp khả thi là thay đổi đường dẫn nhập của Python 13Điều này hoạt động vì đường dẫn nhập bao gồm thư mục chứa 112 và 113. Vấn đề với phương pháp này là đường dẫn nhập của bạn có thể rất lộn xộn và khó hiểuTrên thực tế, bạn đang tạo lại một tính năng của các phiên bản Python đầu tiên được gọi là nhập tương đối ngầm định. Chúng đã bị xóa khỏi ngôn ngữ bởi PEP 328 với lý do sau
Một giải pháp khác là sử dụng nhập tương đối thay thế. Thay đổi quá trình nhập trong 112 như sau 14Giờ đây, bạn có thể bắt đầu ứng dụng của mình thông qua tập lệnh nhập cảnh 15Thật không may, bạn không còn có thể gọi ứng dụng trực tiếp 16Vấn đề là các lần nhập tương đối được giải quyết khác nhau trong các tập lệnh so với các mô-đun đã nhập. Tất nhiên, bạn có thể quay lại và khôi phục quá trình nhập tuyệt đối trước khi chạy tập lệnh trực tiếp hoặc thậm chí bạn có thể thực hiện một số động tác nhào lộn 153 để nhập tệp hoàn toàn hoặc tương đối tùy thuộc vào những gì hoạt độngThậm chí còn có một bản hack bị xử phạt chính thức để làm cho hoạt động nhập tương đối trong các tập lệnh. Thật không may, điều này cũng buộc bạn phải thay đổi 102 trong hầu hết các trường hợp. Trích lời Raymond Hettinger
Thật vậy, một giải pháp tốt hơn—và ổn định hơn—là sử dụng cùng với hệ thống nhập và đóng gói của Python và cài đặt dự án của bạn dưới dạng gói cục bộ bằng cách sử dụng 155Loại bỏ các quảng cáoTạo và cài đặt gói cục bộKhi bạn cài đặt một gói từ PyPI, gói đó có sẵn cho tất cả các tập lệnh trong môi trường của bạn. Tuy nhiên, bạn cũng có thể cài đặt các gói từ máy tính cục bộ của mình và chúng cũng sẽ được cung cấp theo cách tương tự Tạo một gói cục bộ không liên quan đến nhiều chi phí. Đầu tiên, tạo các tệp 156 và 157 tối thiểu trong thư mục 114 bên ngoài 17Về lý thuyết, 159 và 160 có thể là bất cứ thứ gì bạn thích. Tuy nhiên, chúng sẽ được sử dụng bởi 155 khi đề cập đến gói của bạn, vì vậy bạn nên chọn các giá trị dễ nhận biết và không xung đột với các gói khác mà bạn sử dụngMột mẹo là cung cấp cho tất cả các gói cục bộ như vậy một tiền tố chung như 162 hoặc tên người dùng của bạn. 163 nên liệt kê thư mục hoặc các thư mục chứa mã nguồn của bạn. Sau đó, bạn có thể cài đặt gói cục bộ bằng cách sử dụng 155 18Lệnh này sẽ cài đặt gói vào hệ thống của bạn. Sau đó, 114 sẽ được tìm thấy trên đường dẫn nhập của Python, nghĩa là bạn có thể sử dụng nó ở bất cứ đâu mà không phải lo lắng về thư mục tập lệnh, quá trình nhập tương đối hoặc các biến chứng khác. Tùy chọn 166 có nghĩa là có thể chỉnh sửa, tùy chọn này rất quan trọng vì tùy chọn này cho phép bạn thay đổi mã nguồn của gói mà không cần cài đặt lạiGhi chú. Loại tệp thiết lập này hoạt động rất tốt khi bạn tự làm việc với các dự án. Tuy nhiên, nếu bạn định chia sẻ mã với người khác thì bạn nên thêm một số thông tin khác vào tệp thiết lập của mình Để biết thêm chi tiết về các tệp thiết lập, hãy xem Cách xuất bản Gói Python mã nguồn mở lên PyPI Giờ đây, 114 đã được cài đặt trên hệ thống của bạn, bạn có thể sử dụng câu lệnh nhập sau 19Điều này sẽ hoạt động bất kể bạn kết thúc cuộc gọi ứng dụng của mình như thế nào Mẹo. Trong mã của riêng bạn, bạn nên tách biệt các tập lệnh và thư viện một cách có ý thức. Đây là một quy tắc tốt
Bạn có thể có mã mà bạn muốn tự chạy và nhập từ các tập lệnh khác. Trong trường hợp đó, thường đáng để cấu trúc lại mã của bạn để bạn chia phần chung thành một mô-đun thư viện Mặc dù nên tách biệt các tập lệnh và thư viện, nhưng tất cả các tệp Python đều có thể được thực thi và nhập. Trong phần sau, bạn sẽ tìm hiểu thêm về cách tạo các mô-đun xử lý tốt cả hai Gói không gian tênCác mô-đun và gói Python có liên quan rất chặt chẽ với các tệp và thư mục. Điều này khiến Python khác biệt với nhiều ngôn ngữ lập trình khác, trong đó các gói chỉ hoạt động như các không gian tên mà không thực thi cách tổ chức mã nguồn. Xem các cuộc thảo luận trong PEP 402 để biết ví dụ Các gói không gian tên đã có sẵn trong Python kể từ phiên bản 3. 3. Chúng ít phụ thuộc vào hệ thống phân cấp tệp cơ bản. Đặc biệt, các gói không gian tên có thể được chia thành nhiều thư mục. Gói không gian tên được tạo tự động nếu bạn có một thư mục chứa tệp 47 nhưng không có tệp 66. Xem PEP 420 để được giải thích chi tiếtGhi chú. Nói chính xác, các gói không gian tên ẩn đã được giới thiệu trong Python 3. 3. Trong các phiên bản trước của Python, bạn có thể tạo thủ công các gói không gian tên theo một số cách không tương thích khác nhau. PEP 420 thống nhất và đơn giản hóa các phương pháp trước đó Để hiểu rõ hơn về lý do tại sao các gói không gian tên có thể hữu ích, hãy thử triển khai một. Như một ví dụ thúc đẩy, bạn sẽ có một cách khác để giải quyết vấn đề trong Mẫu phương thức xuất xưởng và triển khai của nó trong Python. được cung cấp một đối tượng 170, bạn muốn chuyển đổi nó thành một trong số các biểu diễn chuỗi. Nói cách khác, bạn muốn tuần tự hóa các đối tượng 170Để cụ thể hơn, bạn muốn triển khai mã hoạt động giống như thế này >>> 40Giả sử rằng bạn may mắn và bắt gặp một triển khai của bên thứ ba cho một số định dạng mà bạn cần sắp xếp theo thứ tự và nó được tổ chức dưới dạng gói không gian tên 41Tệp 172 chứa mã có thể tuần tự hóa một đối tượng thành định dạng JSON 42Giao diện bộ nối tiếp này có một chút hạn chế, nhưng nó sẽ đủ để chứng minh cách các gói không gian tên hoạt động Tệp 173 chứa một 174 tương tự có thể chuyển đổi một đối tượng thành XML 43Lưu ý rằng cả hai lớp này đều triển khai cùng một giao diện với các phương thức 175, 176 và 177Sau đó, bạn tạo một lớp 170 có thể sử dụng các bộ nối tiếp này 44Một 170 được xác định bởi ID, tiêu đề và nghệ sĩ của nó. Lưu ý rằng 180 không cần biết nó chuyển đổi sang định dạng nào vì nó sử dụng giao diện chung được xác định trước đóGiả sử rằng bạn đã cài đặt gói 181 của bên thứ ba, bạn có thể sử dụng nó như sau>>> 45Bằng cách cung cấp các đối tượng nối tiếp khác nhau cho 180, bạn sẽ nhận được các bản trình bày khác nhau cho bài hát của mìnhGhi chú. Bạn có thể nhận được một 183 hoặc một 184 khi tự chạy mã. Điều này là do 181 không có trong đường dẫn nhập Python của bạn. Bạn sẽ sớm biết cách giải quyết vấn đề đóCàng xa càng tốt. Tuy nhiên, bây giờ bạn nhận ra rằng bạn cũng cần chuyển đổi các bài hát của mình sang biểu diễn YAML, không được hỗ trợ trong thư viện của bên thứ ba. Nhập sự kỳ diệu của các gói không gian tên. bạn có thể thêm 186 của riêng mình vào gói 181 mà không cần chạm vào thư viện của bên thứ baĐầu tiên, tạo một thư mục trên hệ thống tệp cục bộ của bạn có tên là 181. Điều quan trọng là tên của thư mục phải khớp với tên của gói không gian tên mà bạn đang tùy chỉnh 46Trong tệp 189, bạn xác định 186 của riêng mình. Bạn căn cứ vào gói 191, gói này phải được cài đặt từ PyPI 47Vì YAML và JSON có các định dạng khá giống nhau nên bạn có thể sử dụng lại hầu hết việc triển khai của 192 48Lưu ý rằng 186 dựa trên 192, được nhập từ chính 181. Vì cả 196 và 197 đều là một phần của cùng một gói không gian tên, bạn thậm chí có thể sử dụng nhập tương đối. 198Tiếp tục ví dụ trên, bây giờ bạn cũng có thể chuyển đổi bài hát sang YAML >>> 49Cũng giống như các gói và mô-đun thông thường, các gói không gian tên phải được tìm thấy trên đường dẫn nhập Python. Nếu bạn đang làm theo các ví dụ trước, thì bạn có thể đã gặp sự cố với việc Python không tìm thấy 181. Trong mã thực tế, bạn sẽ sử dụng 155 để cài đặt thư viện của bên thứ ba, do đó, nó sẽ tự động nằm trong đường dẫn của bạnGhi chú. Trong ví dụ ban đầu, việc lựa chọn bộ nối tiếp được thực hiện linh hoạt hơn. Bạn sẽ thấy cách sử dụng các gói không gian tên theo mẫu phương thức xuất xưởng thích hợp sau này Bạn cũng nên đảm bảo rằng thư viện cục bộ của mình có sẵn như một gói thông thường. Như đã giải thích ở trên, bạn có thể thực hiện việc này bằng cách chạy Python từ thư mục thích hợp hoặc bằng cách sử dụng 155 để cài đặt thư viện cục bộ.Trong ví dụ này, bạn đang kiểm tra cách tích hợp gói bên thứ ba giả mạo với gói cục bộ của mình. Nếu 402 là một gói thực, thì bạn sẽ tải xuống từ PyPI bằng cách sử dụng 155. Vì điều này là không thể, bạn có thể mô phỏng nó bằng cách cài đặt 402 cục bộ giống như bạn đã làm trong ví dụ 114 trước đóNgoài ra, bạn có thể gây rối với đường dẫn nhập của mình. Đặt các thư mục 402 và 407 trong cùng một thư mục, sau đó tùy chỉnh đường dẫn Python của bạn như sau>>> 10Giờ đây, bạn có thể sử dụng tất cả các bộ nối tiếp mà không phải lo lắng về việc chúng được xác định trong gói của bên thứ ba hay cục bộ Loại bỏ các quảng cáoHướng dẫn phong cách nhập khẩuPEP 8, hướng dẫn kiểu Python, có một số đề xuất về nhập. Như mọi khi với Python, giữ cho mã của bạn vừa có thể đọc được vừa có thể bảo trì là một điều quan trọng cần cân nhắc. Dưới đây là một số quy tắc chung về cách tạo kiểu cho hàng nhập của bạn
409 và 410 là những công cụ tuyệt vời để thực thi một phong cách nhất quán đối với hàng nhập của bạnĐây là một ví dụ về phần nhập bên trong gói trình đọc nguồn cấp Python thực 11Lưu ý cách nhóm này làm cho các phụ thuộc của mô-đun này rõ ràng. 411 và 412 cần được cài đặt trên hệ thống. Nói chung, bạn có thể cho rằng thư viện tiêu chuẩn có sẵn. Việc tách nhập khẩu từ bên trong gói của bạn cung cấp cho bạn một số tổng quan về các phụ thuộc nội bộ của mã của bạnCó những trường hợp nên bẻ cong các quy tắc này một chút. Bạn đã thấy rằng nhập tương đối có thể là một giải pháp thay thế cho việc tổ chức phân cấp gói. Sau này, bạn sẽ thấy trong một số trường hợp, bạn có thể di chuyển quá trình nhập vào định nghĩa hàm để phá vỡ các chu kỳ nhập như thế nào Nhập tài nguyênĐôi khi, bạn sẽ có mã phụ thuộc vào tệp dữ liệu hoặc các tài nguyên khác. Trong các tập lệnh nhỏ, đây không phải là vấn đề—bạn có thể chỉ định đường dẫn đến tệp dữ liệu của mình và tiếp tục Tuy nhiên, nếu tệp tài nguyên quan trọng đối với gói của bạn và bạn muốn phân phối gói của mình cho những người dùng khác, thì một số thách thức sẽ phát sinh
Đã có một số nỗ lực giải quyết những thách thức này, bao gồm cả 416. Tuy nhiên, với việc đưa 417 vào thư viện chuẩn trong Python 3. 7, hiện có một cách tiêu chuẩn để xử lý các tệp tài nguyênGiới thiệu >>> import math >>> dir() ['__annotations__', '__builtins__', ..., 'math'] >>> dir(math) ['__doc__', ..., 'nan', 'pi', 'pow', ...] 417 417 cấp quyền truy cập vào tài nguyên trong các gói. Trong ngữ cảnh này, tài nguyên là bất kỳ tệp nào nằm trong gói có thể nhập. Tệp có thể tương ứng hoặc không tương ứng với tệp vật lý trên hệ thống tệpĐiều này có một vài lợi thế. Bằng cách sử dụng lại hệ thống nhập, bạn sẽ có cách xử lý nhất quán hơn với các tệp bên trong các gói của mình. Nó cũng cho phép bạn truy cập dễ dàng hơn vào các tệp tài nguyên trong các gói khác. Các tài liệu tổng hợp nó độc đáo
417 đã trở thành một phần của thư viện chuẩn trong Python 3. 7. Tuy nhiên, trên các phiên bản Python cũ hơn, một cổng sau có sẵn dưới dạng 421. Để sử dụng backport, hãy cài đặt nó từ PyPI 12Backport tương thích với Python 2. 7 cũng như Python 3. 4 và các phiên bản mới hơn Có một yêu cầu khi sử dụng 417. các tệp tài nguyên của bạn phải có sẵn bên trong một gói thông thường. Gói không gian tên không được hỗ trợ. Trong thực tế, điều này có nghĩa là tệp phải nằm trong thư mục chứa tệp 66Ví dụ đầu tiên, giả sử bạn có tài nguyên bên trong một gói như thế này 13 66 chỉ là một tệp trống cần thiết để chỉ định 425 như một gói thông thườngYou can then use 426 and 427 to open text and binary files, respectively>>> 14 426 và 427 tương đương với 430 tích hợp với tham số 431 được đặt lần lượt là 432 và 433. Các chức năng thuận tiện để đọc văn bản hoặc tệp nhị phân trực tiếp cũng có sẵn như 434 và 435. Xem tài liệu chính thức để biết thêm thông tinGhi chú. Để liên tục quay lại sử dụng backport trên các phiên bản Python cũ hơn, bạn có thể nhập 417 như sau 15Xem phần mẹo và thủ thuật của hướng dẫn này để biết thêm thông tin Phần còn lại của phần này sẽ hiển thị một số ví dụ phức tạp về việc sử dụng tệp tài nguyên trong thực tế Loại bỏ các quảng cáoVí dụ. Use Data FilesAs a more complete example of using data files, you’ll see how to implement a quiz program based on United Nations population data. First, create a 437 package and download 438 from the UN web page 16Open the CSV file and have a look at the data 17Each line contains the population of a country for a given year and a given variant, which indicates what kind of scenario is used for the projection. The file contains population projections until the year 2100 The following function reads this file and picks out the total population of each country for a given 439 and 440 18The highlighted lines show how 417 is used to open the data file. For more information about working with CSV files, check out Reading and Writing CSV Files in PythonThe above function returns a dictionary with population numbers >>> 19You can do any number of interesting things with this population dictionary, including analysis and visualizations. Here, you’ll create a quiz game that asks users to identify which country in a set is most populous. Playing the game will look something like this 30The details of the implementation are too far outside the topic of this tutorial, so they won’t be discussed here. However, you can expand the section below to see the complete source code Source Code of Population QuizShow/Hide The population quiz consists of two functions, one that reads the population data like you did above and one that runs the actual quiz 31Note that on line 24, you also check that the 442 is less than 443. Locations with a 442 of 443 and above are not proper countries, but aggregates like 446, 447, and so onExample. Add Icons to Tkinter GUIsWhen building graphical user interfaces (GUIs), you often need to include resource files like icons. The following example shows how you can do that using 417. The final app will look quite basic, but it’ll have a custom icon as well as an illustration on the Goodbye buttonThe example uses Tkinter, which is a GUI package available in the standard library. It’s based on the Tk windowing system, originally developed for the Tcl programming language. There are many other GUI packages available for Python. If you’re using a different one, then you should be able add icons to your app using ideas similar to the ones presented here In Tkinter, images are handled by the 449 class. To create a 449, you pass in a path to an image fileRemember, when distributing your package, you’re not even guaranteed that resource files will exist as physical files on the file system. 417 solves this by providing 452. This function will return a path to the resource file, creating a temporary file if necessaryTo make sure any temporary files are cleaned up properly, you should use 452 as a context manager using the keyword 454>>> 32For the full example, assume you have the following file hierarchy 33If you want to try the example yourself, then you can download these files along with the rest of the source code used in this tutorial by clicking the link below Lấy mã nguồn. Nhấp vào đây để lấy mã nguồn mà bạn sẽ sử dụng để tìm hiểu về hệ thống nhập Python trong hướng dẫn này The code is stored in a file with the special name 455. This name indicates that the file is the entry point for the package. Having a 455 file allows your package to be executed with 457 34Để biết thêm thông tin về cách gọi gói bằng 458, hãy xem Cách xuất bản Gói Python nguồn mở lên PyPIGUI được định nghĩa trong một lớp có tên là 459. Lưu ý rằng bạn sử dụng 417 để lấy đường dẫn của tệp hình ảnh 35Nếu bạn muốn tìm hiểu thêm về cách xây dựng GUI với Tkinter, hãy xem Lập trình GUI Python với Tkinter. Tài liệu chính thức cũng có một danh sách tài nguyên hay để bắt đầu và hướng dẫn tại TkDocs là một tài nguyên tuyệt vời khác cho biết cách sử dụng Tk trong các ngôn ngữ khác Ghi chú. Một nguyên nhân gây nhầm lẫn và thất vọng khi làm việc với hình ảnh trong Tkinter là bạn phải đảm bảo hình ảnh không bị thu gom rác. Do cách Python và Tk tương tác, trình thu gom rác trong Python (ít nhất là trong CPython) không đăng ký rằng hình ảnh được sử dụng bởi 461 và 462Để đảm bảo rằng hình ảnh được lưu giữ xung quanh, bạn nên thêm tham chiếu đến chúng theo cách thủ công. Bạn có thể xem các ví dụ về điều này trong đoạn mã trên ở dòng 18 và 31 Loại bỏ các quảng cáoNhập độngMột trong những tính năng xác định của Python là nó là một ngôn ngữ rất năng động. Mặc dù đôi khi đó là một ý tưởng tồi, nhưng bạn có thể thực hiện nhiều việc với chương trình Python khi nó đang chạy, bao gồm thêm thuộc tính vào lớp, xác định lại phương thức hoặc thay đổi chuỗi tài liệu của mô-đun. Chẳng hạn, bạn có thể thay đổi 463 để nó không làm gì cả>>> 36Về mặt kỹ thuật, bạn không định nghĩa lại 463. Thay vào đó, bạn đang xác định một 463 khác che khuất cái tích hợp sẵn. Để quay lại sử dụng 463 ban đầu, bạn có thể xóa tùy chỉnh của mình bằng 467. If you’re so inclined, you can shadow any Python object that is built into the interpreterGhi chú. Trong ví dụ trên, bạn xác định lại 463 bằng hàm lambda. Bạn cũng có thể đã sử dụng một định nghĩa chức năng bình thường>>> 37Để tìm hiểu thêm về các hàm lambda, hãy xem Cách sử dụng các hàm Lambda của Python Trong phần này, bạn sẽ tìm hiểu cách nhập động trong Python. Với chúng, bạn sẽ không phải quyết định nhập nội dung gì cho đến khi chương trình của bạn đang chạy Sử dụng >>> import math >>> dir() ['__annotations__', '__builtins__', ..., 'math'] >>> dir(math) ['__doc__', ..., 'nan', 'pi', 'pow', ...] 469Cho đến giờ, bạn đã sử dụng từ khóa 44 của Python để nhập các mô-đun và gói một cách rõ ràng. Tuy nhiên, toàn bộ máy móc nhập khẩu có sẵn trong gói 469 và điều này cho phép bạn thực hiện việc nhập khẩu của mình linh hoạt hơn. Đoạn script sau hỏi người dùng tên của một mô-đun, nhập mô-đun đó và in chuỗi tài liệu của nó 38 472 trả về một đối tượng mô-đun mà bạn có thể liên kết với bất kỳ biến nào. Sau đó, bạn có thể coi biến đó là một mô-đun được nhập thường xuyên. Bạn có thể sử dụng kịch bản như thế này 39Trong mỗi trường hợp, mô-đun được nhập động bởi 472Ví dụ. Phương thức xuất xưởng với các gói không gian tênNghĩ lại ví dụ về serializers trước đó. Với 181 được triển khai dưới dạng gói không gian tên, bạn có khả năng thêm các bộ nối tiếp tùy chỉnh. Trong ví dụ ban đầu từ hướng dẫn trước, các bộ nối tiếp được cung cấp thông qua một nhà máy sản xuất bộ nối tiếp. Sử dụng 469, bạn có thể làm điều gì đó tương tựThêm mã sau vào gói không gian tên 181 cục bộ của bạn 30The 477 factory can create serializers dynamically based on the 478 parameter, and 479 can then apply the serializer to any object that implements a 180 methodThe factory makes some strong assumptions about the naming of both the module and the class containing the individual serializers. In the next section, you’ll learn about a plugin architecture that allows more flexibility Bây giờ bạn có thể tạo lại ví dụ trước đó như sau >>> 31Trong trường hợp này, bạn không cần phải nhập rõ ràng từng bộ nối tiếp nữa. Instead, you specify the name of a serializer with a string. Chuỗi thậm chí có thể được chọn bởi người dùng của bạn khi chạy Note. In a regular package, you probably would have implemented 477 and 479 in an 66 file. That would have allowed you to simply import 181 and then call 485However, namespace packages aren’t allowed to use 66, so you need to implement these functions in a separate module insteadThe final example shows that you also get a decent error message if you try to serialize to a format that hasn’t been implemented Loại bỏ các quảng cáoExample. A Package of PluginsLet’s look at another example of using dynamic imports. You can use the following module to set up a flexible plugin architecture in your code. This is similar to the previous example, in which you could plug in serializers for different formats by adding new modules One application that uses plugins effectively is the Glue exploratory visualization tool. Glue can read many different data formats out of the box. However, if your data format isn’t supported, then you can write your own custom data loader You do this by adding a function that you decorate and place in a special location to make it easy for Glue to find. You don’t need to alter any part of the Glue source code. See the documentation for all the details You can set up a similar plugin architecture that you can use in your own projects. Within the architecture, there are two levels
The 487 module that exposes the plugin architecture has the following functions 32The factory functions are used to conveniently add functionality to plugin packages. You’ll see some examples of how they’re used shortly Looking at all the details of this code is outside the scope of this tutorial. If you’re interested, then you can see an implementation by expanding the section below Complete Source Code of plugins. pyShow/Hide The following code shows the implementation of 488 described above 33This implementation is a bit simplified. In particular, it doesn’t do any explicit error handling. Check out the PyPlugs project for a more complete implementation You can see that 489 uses 490 to dynamically load plugins. Additionally, 491 uses 492 to list all available plugins in a given packageLet’s look at some examples of how to use plugins. The first example is a 493 package that you can use to add many different greetings to your app. A full plugin architecture is definitely overkill for this example, but it shows how the plugins workAssume you have the following 493 package 34Mỗi mô-đun 493 xác định một hàm nhận một đối số 159. Note how they’re all registered as plugins using the 497 decorator 35To learn more about decorators and how they’re used, check out Primer on Python Decorators Note. To simplify the discovery and import of plugins, each plugin’s name is based on the name of the module that contains it instead of the function name. This restricts you to having only one plugin per file To finish setting up 493 as a plugin package, you can use the factory functions in 487 to add functionality to the 493 package itself 36You can now use 101 and 102 as follows>>> 37Note that 101 automatically discovers all the plugins that are available in the packageYou can also more dynamically choose which plugin to call. In the following example, you choose a plugin at random. However, you could also select a plugin based on a configuration file or user input >>> 38To discover and call the different plugins, you need to import them. Let’s have a quick look at how 487 handles imports. The main work is done in the following two functions inside 488 39 489 looks deceptively straightforward. It uses 469 to import a module. But there are a couple of things also happening in the background
491 discovers all the plugins within a package. Here’s how it works
Let’s end this section with a final version of the serializers namespace package. One outstanding issue was that the 477 factory made strong assumptions about the naming of the serializer classes. You can make this more flexible using pluginsFirst, add a line registering each of the serializers. Here is an example of how it’s done in the 197 serializer 70Tiếp theo, cập nhật 114 để sử dụng 487 71You implement 477 using 117 since that will automatically instantiate each serializer. With this refactoring, the serializers work just the same as earlier. However, you have more flexibility in naming your serializer classesFor more information about using plugins, check out PyPlugs on PyPI and the Plug-ins. Adding Flexibility to Your Apps presentation from PyCon 2019 Loại bỏ các quảng cáoThe Python Import SystemYou’ve seen many ways to take advantage of Python’s import system. In this section, you’ll learn a bit more about what happens behind the scenes as modules and packages are imported As with most parts of Python, the import system can be customized. You’ll see several ways that you can change the import system, including automatically downloading missing packages from PyPI and importing data files as if they were modules Import InternalsThe details of the Python import system are described in the official documentation. At a high level, three things happen when you import a module (or package). The module is
For the usual imports—those done with the 44 statement—all three steps happen automatically. When you use 469, however, only the first two steps are automatic. You need to bind the module to a variable or namespace yourselfFor instance, the following methods of importing and renaming 53 are roughly equivalent>>> 72Of course, in normal code you should prefer the former One thing to note is that, even when you import only one attribute from a module, the whole module is loaded and executed. The rest of the contents of the module just aren’t bound to the current namespace. One way to prove this is to have a look at what’s known as the module cache >>> 73 121 acts as a module cache. It contains references to all modules that have been importedThe module cache plays a very important role in the Python import system. The first place Python looks for modules when doing an import is in 121. If a module is already available, then it isn’t loaded againThis is a great optimization, but it’s also a necessity. If modules were reloaded each time they were imported, then you could end up with inconsistencies in certain situations, such as when the underlying source code changes while a script is running Recall the import path you saw earlier. It essentially tells Python where to search for modules. However, if Python finds a module in the module cache, then it won’t bother searching the import path for the module Example. Singletons as ModulesIn object-oriented programming, a singleton is a class with at most one instance. While it’s possible to implement singletons in Python, most good uses of singletons can be handled by modules instead. You can trust the module cache to instantiate a class only once As an example, let’s return to the United Nations population data you saw earlier. The following module defines a class wrapping the population data 74Reading the data from disk takes some time. Since you don’t expect the data file to change, you instantiate the class when you load the module. The name of the class starts with an underscore to indicate to users that they shouldn’t use it You can use the 123 singleton to create a Matplotlib graph showing the population projection for the most populous countries>>> 75This creates a chart like the following Note that loading the data at import time is a kind of antipattern. Ideally, you want your imports to be as free of side effects as possible. A better approach would be to load the data lazily when you need it. You can do this quite elegantly using properties. Expand the following section to see an example Lazily Loading Population DataShow/Hide The lazy implementation of 124 stores the population data in 125 the first time it’s read. The 126 property handles this caching of data 76Now the data won’t be loaded at import time. Instead, it’ll be imported the first time you access the 127 dictionary. For more information about properties and the more general concept of descriptors, see Python Descriptors. An IntroductionLoại bỏ các quảng cáoReloading ModulesThe module cache can be a little frustrating when you’re working in the interactive interpreter. It’s not trivial to reload a module after you change it. For example, take a look at the following module 77As part of testing and debugging this module, you import it in a Python console >>> 78Let’s say you realize that you have a bug in your code, so you update the 128 file in your editor 79Returning to your console, you import the updated module to see the effect of your fix >>> 78Why is the answer still 129? The module cache is doing its (now frustrating) magic. since Python imported 130 earlier, it sees no reason to load the module again even though you just changed itThe most straightforward solution to this is to exit the Python console and restart it. This forces Python to clear its module cache as well >>> 01However, restarting the interpreter isn’t always feasible. You might be in a more complicated session that has taken you a long time to set up. If that’s the case, then you can use 131 to reload a module instead>>> 02Note that 132 requires a module object, not a string like 472 does. Also, be aware that 132 has some caveats. In particular, variables referring to objects within a module are not re-bound to new objects when that module is reloaded. See the documentation for more detailsFinders and LoadersYou saw earlier that creating modules with the same name as standard libraries can create problems. For example, if you have a file named 135 in Python’s import path, then you won’t be able to import 49 from the standard libraryThis isn’t always the case, though. Create a file named 137 with the following content 03Next, open a Python interpreter and import this new module >>> 04Something weird happened. It doesn’t seem like Python imported your new 138 module. Instead, it imported the 138 module from the standard library. Why are the standard library modules behaving inconsistently? You can get a hint by inspecting the modules>>> 05You can see that 49 is imported from a file, whereas 138 is some kind of built-in module. It seems that built-in modules aren’t shadowed by local onesNote. Các mô-đun tích hợp được biên dịch thành trình thông dịch Python. Typically, they’re foundational modules like 142, 143, and 138. Which modules are built in depends on your Python interpreter, but you can find their names in 145Let’s dig even deeper into Python’s import system. This will also show why built-in modules aren’t shadowed by local ones. There are several steps involved when importing a module
You can extend the Python import system by implementing your own finder and, if necessary, your own loader. You’ll see a more useful example of a finder later. For now, you’ll learn how to do basic (and possibly silly) customizations of the import system 147 controls which finders are called during the import process>>> 06First, note that this answers the question from earlier. built-in modules aren’t shadowed by local modules because the built-in finder is called before the import path finder, which finds local modules. Second, note that you can customize 147 to your likingTo quickly mess up your Python session, you can remove all finders >>> 07Since there are no finders, Python can’t find or import new modules. However, Python can still import modules that are already in the module cache since it looks there before calling any finders In the example above, 469 was already loaded under the hood before you cleared the list of finders. If you really want to make your Python session completely unusable, then you can also clear the module cache, 121The following is a slightly more useful example. You’ll write a finder that prints a message to the console identifying the module being imported. The example shows how to add your own finder, although it doesn’t actually attempt to find a module 08All finders must implement a 151 class method, which should try to find a given module. There are three ways that 151 can terminate
The 155 prints a message to the console and then explicitly returns 153 to indicate that other finders should figure out how to actually import the moduleNote. Since Python implicitly returns 153 from any function or method without an explicit 158, you can leave out line 9. However, in this case it’s good to include 159 to make it clear that 155 doesn’t find a moduleBy inserting 155 first in the list of finders, you get a running list of all modules being imported>>> 09You can, for instance, see that importing 162 triggers the import of several other modules that 162 depends on. Note that the verbose option to the Python interpreter, 164, gives the same information and much, much moreFor another example, say that you’re on a quest to rid the world of regular expressions. (Now, why would you want such a thing? Regular expressions are great. ) You could implement the following finder that bans the 165 regular expressions module 20Nâng cao một 183 đảm bảo rằng không có công cụ tìm nào sau này trong danh sách công cụ tìm sẽ được thực thi. This effectively stops you from using regular expressions in Python>>> 21Even though you’re importing only 162, that module is importing 165 behind the scenes, so an error is raisedExample. Automatically Install From PyPIBecause the Python import system is already quite powerful and useful, there are many more ways to mess it up than there are to extend it in a useful way. However, the following example can be useful in certain situations The Python Package Index (PyPI) is your one-stop cheese shop for finding third-party modules and packages. It’s also the place from which 155 downloads packagesIn other Real Python tutorials, you may have seen instructions to use 170 to install the third-party modules and packages you need for following along with examples. Wouldn’t it be great to have Python automatically install missing modules for you?Warning. In most cases, it really wouldn’t be great to have Python install modules automatically. For instance, in most production settings you want to stay in control of your environment. Furthermore, the documentation cautions against using 155 this wayTo avoid messing up your Python installation, you should play with this code only in environments that you wouldn’t mind deleting or reinstalling The following finder attempts to install modules using 155 22Compared to the finders you saw earlier, this one is slightly more complicated. By putting this finder last in the list of finders, you know that if you call 173, then the module won’t be found on your system. The job of 151 is therefore just to do the 175. If the installation works, then the module spec will be created and returnedTry to use the 176 library without installing it yourself>>> 23Normally, 177 would’ve raised a 183, but in this case 176 is installed and importedWhile the 173 seemingly works, there are some challenges with this approach. One major problem is that the import name of a module doesn’t always correspond to its name on PyPI. For example, the Real Python feed reader is called 181 on PyPI, but the import name is simply 182Using 173 to import and install 182 ends up installing the wrong package>>> 24This could have disastrous consequences for your project One situation in which automatic installations can be quite helpful is when you’re running Python in the cloud with more limited control over your environment, such as when you’re running Jupyter-style notebooks at Google Colaboratory. The Colab notebook environment is great for doing cooperative data exploration A typical notebook comes with many data science packages installed, including NumPy, Pandas, and Matplotlib, and you can add new packages with 155. But you can also activate automatic installationSince 186 isn’t available locally on the Colab server, the code is copied into the first cell of the notebookExample. Import Data FilesThe final example in this section is inspired by Aleksey Bilogur’s great blog post Import Almost Anything in Python. An Intro to Module Loaders and Finders. You’ve already seen how to use 417 to import datafiles. Here, you’ll instead implement a custom loader that can import a CSV file directlyEarlier, you worked with a huge CSV file with population data. To make the custom loader example more manageable, consider the following smaller 188 file 25The first line is a header naming three fields, and the following two rows of data each contain information about an employee. For more information about working with CSV files, check out Reading and Writing CSV Files in Python Your goal in this section is to write a finder and a loader that allow you to import the CSV file directly so that you can write code like the following >>> 26The job of the finder will be to search for and recognize CSV files. Công việc của trình tải sẽ là nhập dữ liệu CSV. Often, you can implement finders and corresponding loaders in one common class. That’s the approach you’ll take here 27There’s quite a bit of code in this example. Luckily, most of the work is done in 151 and 190. Let’s look at them in more detailAs you saw earlier, 151 is responsible for finding the module. In this case, you’re looking for CSV files, so you create a filename with a 192 suffix. 159 contains the full name of the module that is imported. For example, if you use 194, then 159 will be 196. In this case, the filename will be 188For top-level imports, 198 will be 153. In that case, you look for the CSV file in the full import path, which will include the current working directory. If you’re importing a CSV file within a package, then 198 will be set to the path or paths of the package. If you find a matching CSV file, then a module spec is returned. This module spec tells Python to load the module using 301The CSV data is loaded by 190. You can use 303 from the standard library to do the actual parsing of the file. Like most things in Python, modules are backed by dictionaries. By adding the CSV data to 304, you make it available as attributes of the moduleFor instance, adding 305 to the module dictionary on line 44 allows you to list the field names in the CSV file as follows>>> 28In general, CSV field names can contain spaces and other characters that aren’t allowed in Python attribute names. Before adding the fields as attributes on the module, you sanitize the field names using a regular expression. This is done in 306 starting on line 51You can see an example of this effect in the 307 field name above. If you look at the original CSV file, then you’ll see that the header says 308 with a space instead of an underscoreBy hooking this 301 into the Python import system, you get a fair bit of functionality for free. For example, the module cache will make sure that the data file is loaded only onceImport Tips and TricksTo round out this tutorial, you’ll see a few tips about how to handle certain situations that come up from time to time. You’ll see how to deal with missing packages, cyclical imports, and even packages stored inside ZIP files Handle Packages Across Python VersionsSometimes you need to deal with packages that have different names depending on the Python version. You’ve already seen one example of this. 417 has only been available since Python 3. 7. In earlier versions of Python, you need to install and use 421 insteadAs long as the different versions of the package are compatible, you can handle this by renaming the package with 312 15In the rest of the code, you can refer to 313 and not worry about whether you’re using 417 or 421Normally, it’s easiest to use a 153 statement to figure out which version to use. Another option is to inspect the version of the Python interpreter. However, this may add some maintenance cost if you need to update the version numbersYou could rewrite the previous example as follows 00This would use 417 on Python 3. 7 and newer while falling back to 421 on older versions of Python. See the 319 project for good and future-proof advice on how to check which Python version is runningHandle Missing Packages. Sử dụng một thay thếThe following use case is closely related to the previous example. Assume there’s a compatible reimplementation of a package. The reimplementation is better optimized, so you want to use it if it’s available. However, the original package is more easily available and also delivers acceptable performance One such example is 320, which is an optimized version of 321 from the standard library. You can handle these preferences the same way you handled different package names earlier 01This will use 320 if it’s available and fall back to 321 if notAnother similar example is the UltraJSON package, an ultrafast JSON encoder and decoder that can be used as a replacement for 196 in the standard library 02By renaming 325 to 196, you don’t have to worry about which package was actually importedHandle Missing Packages. Use a Mock InsteadA third, related example is adding a package that provides a nice-to-have feature that’s not strictly necessary for your app. Again, this can be solved by adding 153 to your imports. The extra challenge is how you will replace the optional package if it’s not availableFor a concrete example, say that you’re using Colorama to add colored text in the console. Colorama mainly consists of special string constants that add color when printed >>> 03Unfortunately, the color doesn’t render in the example above. In your terminal it’ll look something like this Before you start using Colorama colors, you should call 328. Setting 329 to 330 means that the color directives will be automatically reset at the end of the string. It’s a useful setting if you want to color just one line at a timeIf you’d rather have all your output be (for example) blue, then you can let 329 be 332 and add 333 to the beginning of your script. The following colors are available>>> 04You can also use 334 to control the style of your text. You can choose between 335, 336, and 337Finally, 338 provides codes for controlling the position of the cursor. You can use it to display the progress or status of a running script. The following example displays a countdown from 339 05Note how the counter stays in place instead of printing on separate lines as it normally would Let’s get back to the task at hand. For many applications, adding color to your console output is cool but not critical. To avoid adding yet another dependency to your app, you want to use Colorama only if it’s available on the system and not break the app if it isn’t To do this, you can take inspiration from testing and its use of mocks. A mock can substitute for another object while allowing you to control its behavior. Here’s a naïve attempt at mocking Colorama >>> 06This doesn’t quite work, because 340 is represented by a string that messes up your output. Instead, you want to create an object that always renders as the empty stringIt’s possible to change the return value of 177 on 342 objects. However, in this case, it’s more convenient to write your own mock 07 343 là một chuỗi rỗng cũng sẽ trả về chuỗi rỗng khi nó được gọi. This effectively gives us a reimplementation of Colorama, just without the colorsThe final trick is that 344 returns itself, so that all colors, styles, and cursor movements that are attributes on 345, 346, 347, and 348 are mocked as wellThe 349 module is designed to be a drop-in replacement for Colorama, so you can update the countdown example using search and replace 08Nếu bạn chạy tập lệnh này trên hệ thống không có Colorama thì tập lệnh vẫn hoạt động nhưng có thể trông không đẹp bằng With Colorama installed, you should see the same results as earlier Nhập tập lệnh dưới dạng mô-đunMột điểm khác biệt giữa tập lệnh và mô-đun thư viện là tập lệnh thường làm một việc gì đó, trong khi thư viện cung cấp chức năng. Cả tập lệnh và thư viện đều nằm trong các tệp Python thông thường và đối với Python, không có sự khác biệt nào giữa chúng Thay vào đó, sự khác biệt là ở chỗ tệp được sử dụng như thế nào. nó nên được thực thi với 350 hay được nhập với 351 bên trong một tập lệnh khác?Đôi khi, bạn sẽ có một mô-đun hoạt động như cả tập lệnh và thư viện. Bạn có thể thử cấu trúc lại mô-đun của mình thành hai tệp khác nhau Một ví dụ về điều này trong thư viện tiêu chuẩn là gói 196. Bạn thường sử dụng nó như một thư viện, nhưng nó cũng đi kèm với một tập lệnh có thể chỉnh sửa các tệp JSON. Giả sử bạn có tệp 353 sau 09Vì JSON thường chỉ được đọc bởi máy móc nên nhiều tệp JSON không được định dạng theo kiểu có thể đọc được. Trên thực tế, việc các tệp JSON bao gồm một dòng văn bản rất dài là điều khá phổ biến. 354 là tập lệnh sử dụng thư viện 196 để định dạng JSON theo cách dễ đọc hơn 10Bây giờ cấu trúc của tệp JSON trở nên dễ nắm bắt hơn nhiều. Bạn có thể sử dụng tùy chọn 356 để sắp xếp các khóa theo thứ tự bảng chữ cáiMặc dù việc chia nhỏ tập lệnh và thư viện là một phương pháp hay, nhưng Python có một thành ngữ giúp có thể coi một mô-đun vừa là tập lệnh vừa là thư viện cùng một lúc. Như đã lưu ý trước đó, giá trị của biến mô-đun 125 đặc biệt được đặt trong thời gian chạy dựa trên việc mô-đun được nhập hay chạy dưới dạng tập lệnhHãy thử nghiệm nó. Tạo tập tin sau 11Nếu bạn chạy tệp này, thì bạn sẽ thấy rằng 125 được đặt thành giá trị đặc biệt 126 12Tuy nhiên, nếu bạn nhập mô-đun, thì 125 được đặt thành tên của mô-đun>>> 13Hành vi này được tận dụng trong mẫu sau 14Hãy sử dụng điều này trong một ví dụ lớn hơn. Với nỗ lực giúp bạn luôn trẻ trung, tập lệnh sau sẽ thay thế bất kỳ độ tuổi “già” nào ( 361 trở lên) bằng 129 15Bạn có thể chạy tập lệnh này dưới dạng tập lệnh và nó sẽ tương tác làm cho độ tuổi bạn nhập trẻ hơn 16Bạn cũng có thể sử dụng mô-đun làm thư viện có thể nhập. Bài kiểm tra 124 ở dòng 12 đảm bảo rằng không có tác dụng phụ khi bạn nhập thư viện. Chỉ các chức năng 364 và 365 được xác định. Ví dụ, bạn có thể sử dụng thư viện này như sau>>> 17Nếu không có sự bảo vệ của thử nghiệm 124, quá trình nhập sẽ kích hoạt 367 tương tác và khiến cho việc sử dụng 368 làm thư viện trở nên rất khó khănChạy tập lệnh Python từ tệp ZIPMột tính năng hơi khó hiểu của Python là nó có thể chạy các tập lệnh được đóng gói thành các tệp ZIP. Ưu điểm chính của điều này là bạn có thể phân phối một gói đầy đủ dưới dạng một tệp Tuy nhiên, lưu ý rằng điều này vẫn yêu cầu cài đặt Python trên hệ thống. Nếu bạn muốn phân phối ứng dụng Python của mình dưới dạng tệp thực thi độc lập, hãy xem Sử dụng PyInstaller để dễ dàng phân phối ứng dụng Python Nếu bạn cung cấp cho trình thông dịch Python một tệp ZIP, thì nó sẽ tìm tệp có tên 455 bên trong kho lưu trữ ZIP, giải nén và chạy tệp đó. Như một ví dụ cơ bản, tạo tệp 455 sau 18Điều này sẽ in một tin nhắn khi bạn chạy nó 19Bây giờ hãy thêm nó vào kho lưu trữ ZIP. Bạn có thể làm điều này trên dòng lệnh 20Trên Windows, thay vào đó, bạn có thể sử dụng trỏ và nhấp. Chọn tệp trong File Explorer, sau đó nhấp chuột phải và chọn Gửi đến → thư mục đã nén (zipped) Vì 126 không phải là một cái tên mang tính mô tả nhiều nên bạn đã đặt tên cho tệp ZIP là 372. Bây giờ bạn có thể gọi nó trực tiếp bằng Python 21Lưu ý rằng tập lệnh của bạn biết rằng nó nằm bên trong 372. Hơn nữa, gốc của tệp ZIP của bạn được thêm vào đường dẫn nhập của Python để tập lệnh của bạn có thể nhập các mô-đun khác trong cùng một tệp ZIPNghĩ lại ví dụ trước đó mà bạn đã tạo một bài kiểm tra dựa trên dữ liệu dân số. Có thể phân phối toàn bộ ứng dụng này dưới dạng một tệp ZIP. 417 sẽ đảm bảo tệp dữ liệu được trích xuất từ kho lưu trữ ZIP khi cầnỨng dụng bao gồm các tệp sau 22Bạn có thể thêm chúng vào tệp ZIP giống như cách bạn đã làm ở trên. Tuy nhiên, Python đi kèm với một công cụ có tên là 375 hợp lý hóa quy trình đóng gói các ứng dụng vào kho lưu trữ ZIP. Bạn sử dụng nó như sau 23Lệnh này về cơ bản thực hiện hai việc. nó tạo ra một điểm vào và đóng gói ứng dụng của bạn Hãy nhớ rằng bạn cần tệp 455 làm điểm vào bên trong kho lưu trữ ZIP của mình. Nếu bạn cung cấp cho tùy chọn 458 thông tin về cách bắt đầu ứng dụng của bạn, thì 375 sẽ tạo tệp này cho bạn. Trong ví dụ này, 455 được tạo trông như thế này 24 455 này được đóng gói, cùng với nội dung của thư mục 381, vào một kho lưu trữ ZIP có tên là 382. Hậu tố 383 báo hiệu rằng đây là tệp Python được gói trong kho lưu trữ ZIPGhi chú. Theo mặc định, 375 không nén bất kỳ tệp nào. Nó chỉ đóng gói chúng thành một tệp duy nhất. Bạn cũng có thể yêu cầu 375 nén các tệp bằng cách thêm tùy chọn 386Tuy nhiên, tính năng này chỉ khả dụng trong Python 3. 7 trở lên. Xem tài liệu 375 để biết thêm thông tinOn Windows, 383 files should already be registered as Python files. On Mac and Linux, you can have 375 create executable files by using the 390 interpreter option and specifying which interpreter to use 25Tùy chọn 390 thêm một shebang ( 392) cho hệ điều hành biết cách chạy tệp. Additionally, it makes the 383 file executable so that you can run the file just by typing its name 26Notice the 394 in front of the filename. This is a typical trick on Mac and Linux to run executable files in the current directory. If you move the file to a directory on your 395, or if you’re using Windows, then you should be able to use only the filename. 382Note. Trên Python 3. 6 trở lên, lệnh trước đó sẽ không thành công với thông báo nói rằng không thể tìm thấy tài nguyên dữ liệu dân số trong thư mục 437. Điều này là do một giới hạn trong 398Một cách giải quyết khác là cung cấp đường dẫn tuyệt đối tới 382. Trên Mac và Linux, bạn có thể làm điều này bằng thủ thuật sau 27Lệnh 300 mở rộng đến đường dẫn của thư mục hiện tạiHãy kết thúc phần này bằng cách xem xét một hiệu ứng tuyệt vời khi sử dụng 417. Hãy nhớ rằng bạn đã sử dụng đoạn mã sau để mở tệp dữ liệu 28Một cách phổ biến hơn để mở tệp dữ liệu là xác định vị trí của chúng dựa trên thuộc tính 413 của mô-đun của bạn 29Cách tiếp cận này thường hoạt động tốt. Tuy nhiên, nó sẽ bị hỏng khi ứng dụng của bạn được đóng gói thành tệp ZIP 30Tệp dữ liệu của bạn nằm trong kho lưu trữ ZIP nên 430 không thể mở tệp đó. Mặt khác, 417 sẽ trích xuất dữ liệu của bạn thành một tệp tạm thời trước khi mở tệp đóXử lý nhập khẩu theo chu kỳNhập theo chu kỳ xảy ra khi bạn có hai hoặc nhiều mô-đun nhập lẫn nhau. Cụ thể hơn, hãy tưởng tượng rằng mô-đun 305 sử dụng 306 và mô-đun 307 nhập khẩu tương tự 305Hệ thống nhập của Python ở một mức độ nào đó được thiết kế để xử lý các chu kỳ nhập. Chẳng hạn, đoạn mã sau—mặc dù không hữu dụng lắm—chạy tốt 31Cố gắng nhập 305 trong trình thông dịch tương tác cũng nhập 307>>> 32Lưu ý rằng 307 được nhập vào giữa quá trình nhập của 305, chính xác tại câu lệnh 306 trong mã nguồn của 305. Lý do điều này không kết thúc trong đệ quy vô tận là người bạn cũ của chúng tôi bộ đệm mô-đunKhi bạn nhập 315, một tham chiếu đến 305 sẽ được thêm vào bộ nhớ cache của mô-đun ngay cả trước khi tải 305. Khi 307 cố gắng nhập 305 sau đó, nó chỉ cần sử dụng tham chiếu trong bộ đệm mô-đunBạn cũng có thể có các mô-đun làm điều gì đó hữu ích hơn một chút. Nếu bạn xác định các thuộc tính và chức năng trong các mô-đun của mình, thì tất cả vẫn hoạt động 33Nhập 305 hoạt động giống như trước đây>>> 32Các sự cố liên quan đến nhập đệ quy bắt đầu xuất hiện khi bạn thực sự sử dụng mô-đun khác tại thời điểm nhập thay vì chỉ xác định các hàm sẽ sử dụng mô-đun khác sau này. Thêm một dòng vào 321 35Bây giờ Python bị nhầm lẫn khi nhập >>> 36Thông báo lỗi lúc đầu có vẻ hơi khó hiểu. Nhìn lại mã nguồn, bạn có thể xác nhận rằng 130 được định nghĩa trong mô-đun 305Vấn đề là 130 không được xác định trong 305 tại thời điểm 307 được nhập. Do đó, 327 được sử dụng bởi lệnh gọi tới 328Để thêm vào sự nhầm lẫn, bạn sẽ không gặp vấn đề gì khi nhập 307>>> 37Vào thời điểm 307 gọi 328, 305 được nhập đầy đủ và 327 được xác định rõ. Cuối cùng, do bộ đệm mô-đun mà bạn đã thấy trước đó, 315 có thể hoạt động nếu bạn thực hiện một số thao tác nhập khác trước>>> 38Vậy làm thế nào bạn có thể tránh bị sa lầy và bối rối bởi việc nhập khẩu theo chu kỳ? Thông thường, thời gian dễ dàng nhất để khắc phục các lần nhập theo chu kỳ là trước khi bạn triển khai chúng. Nếu bạn thấy các chu kỳ trong bản phác thảo kiến trúc của mình, hãy xem xét kỹ hơn và cố gắng phá vỡ các chu kỳ đó Tuy nhiên, đôi khi việc giới thiệu một chu kỳ nhập khẩu là hợp lý. Như bạn đã thấy ở trên, đây không phải là vấn đề miễn là các mô-đun của bạn chỉ định nghĩa các thuộc tính, hàm, lớp, v.v. Mẹo thứ hai—cũng là một phương pháp thiết kế tốt—là giữ cho các mô-đun của bạn không có tác dụng phụ khi nhập Nếu bạn thực sự cần các mô-đun có chu kỳ nhập và tác dụng phụ, thì vẫn còn một cách khác. thực hiện nhập cục bộ của bạn bên trong các chức năng Lưu ý rằng trong đoạn mã sau, 306 được thực hiện bên trong 328. Điều này có hai hậu quả. Đầu tiên, 307 chỉ khả dụng bên trong hàm 328. Quan trọng hơn, quá trình nhập không xảy ra cho đến khi bạn gọi 328 sau khi 305 đã được nhập đầy đủ 39Bây giờ không có vấn đề gì khi nhập và sử dụng 305>>> 40Lưu ý rằng trên thực tế, 307 không được nhập cho đến khi bạn gọi 328. Để có một góc nhìn khác về nhập khẩu theo chu kỳ, hãy xem ghi chú kinh điển của Fredrik LundhNhập hồ sơMột mối quan tâm khi nhập một số mô-đun và gói là nó sẽ thêm vào thời gian khởi động tập lệnh của bạn. Tùy thuộc vào ứng dụng của bạn, điều này có thể hoặc không quan trọng Kể từ khi phát hành Python 3. 7, bạn đã có một cách nhanh chóng để biết cần bao nhiêu thời gian để nhập các gói và mô-đun. Trăn 3. 7 hỗ trợ tùy chọn dòng lệnh 344, đo lường và in lượng thời gian mỗi mô-đun cần để nhập 41Cột 345 hiển thị thời gian nhập tích lũy (tính bằng micrô giây) trên cơ sở từng gói. Bạn có thể đọc danh sách như sau. Python đã dành 346 micro giây để nhập đầy đủ 347, bao gồm cả việc nhập 138, 49 và triển khai C 350Cột 351 hiển thị thời gian cần thiết để chỉ nhập mô-đun đã cho, không bao gồm mọi lần nhập đệ quy. Bạn có thể thấy rằng 138 mất 353 micro giây để nhập, 49 mất 355, 350 mất 357 và bản thân việc nhập 347 mất 359 micro giây. Nói chung, điều này làm tăng thêm thời gian tích lũy là 346 micro giây (trong phạm vi lỗi làm tròn)Hãy xem ví dụ về 361 từ phần Colorama 42Trong ví dụ này, việc nhập 349 mất gần 0. 013 giây. Hầu hết thời gian đó được dành để nhập Colorama và các phụ thuộc của nó. Cột 351 hiển thị thời gian nhập không bao gồm nhập lồng nhauĐối với một ví dụ cực đoan, hãy xem xét đơn lẻ 124 từ trước đó. Vì nó đang tải một tệp dữ liệu lớn nên nhập cực kỳ chậm. Để kiểm tra điều này, bạn có thể chạy 365 dưới dạng tập lệnh với tùy chọn 386 43Trong trường hợp này, mất gần 2 giây để nhập 124, trong đó khoảng 1. 6 giây được sử dụng trong chính mô-đun, chủ yếu để tải tệp dữ liệu 344 là một công cụ tuyệt vời để tối ưu hóa quá trình nhập của bạn. Nếu bạn cần thực hiện giám sát và tối ưu hóa tổng quát hơn cho mã của mình, hãy xem Hàm hẹn giờ Python. Ba cách để theo dõi mã của bạnPhần kết luậnTrong hướng dẫn này, bạn đã biết hệ thống nhập Python. Giống như nhiều thứ trong Python, nó khá đơn giản để sử dụng cho các tác vụ cơ bản như nhập mô-đun và gói. Đồng thời, hệ thống nhập khẩu khá phức tạp, linh hoạt và có thể mở rộng. Bạn đã học được một số thủ thuật liên quan đến nhập mà bạn có thể tận dụng trong mã của riêng mình Trong hướng dẫn này, bạn đã học cách
Trong suốt hướng dẫn, bạn đã thấy nhiều liên kết đến thông tin thêm. Nguồn có thẩm quyền nhất trên hệ thống nhập Python là tài liệu chính thức
Bạn có thể sử dụng kiến thức về nhập Python của mình bằng cách làm theo các ví dụ trong hướng dẫn này. Nhấp vào liên kết bên dưới để truy cập vào mã nguồn Lấy mã nguồn. Nhấp vào đây để lấy mã nguồn mà bạn sẽ sử dụng để tìm hiểu về hệ thống nhập Python trong hướng dẫn này Đánh dấu là đã hoàn thành 🐍 Thủ thuật Python 💌 Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python Gửi cho tôi thủ thuật Python » Giới thiệu về Geir Arne Hjelle Geir Arne là một Pythonista cuồng nhiệt và là thành viên của nhóm hướng dẫn Real Python » Thông tin thêm về Geir ArneMỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là Aldren Brad Đan Joanna Gia-cốp Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia Nâng cao kỹ năng Python của bạn » Bậc thầy Kỹ năng Python trong thế giới thực Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia Nâng cao kỹ năng Python của bạn » Bạn nghĩ sao? Đánh giá bài viết này Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì? Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. Nhận các mẹo để đặt câu hỏi hay và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi |