Chuyển đến nội dung chính
Show
Python trung cấpNâng cao kỹ năng khoa học dữ liệu của bạn bằng cách tạo trực quan hóa bằng Matplotlib và thao tác với DataFrames bằng gấu trúcCó liên quan Dữ liệu văn bản trong Python Cheat SheetChào mừng bạn đến với bảng gian lận của chúng tôi để làm việc với dữ liệu văn bản trong Python. Chúng tôi đã biên soạn một danh sách các hàm và gói hữu ích nhất để dọn dẹp, xử lý và phân tích dữ liệu văn bản trong Python, cùng với các ví dụ và giải thích rõ ràng, vì vậy bạn sẽ có mọi thứ cần biết về cách làm việc với dữ liệu văn bản trong Python.Hướng dẫn về tập hợp và lý thuyết tập hợp trong PythonTìm hiểu về bộ Python. chúng là gì, cách tạo chúng, khi nào sử dụng chúng, các chức năng tích hợp và mối quan hệ của chúng với các hoạt động lý thuyết thiết lậpHướng dẫn về gấu trúc. Khung dữ liệu trong PythonKhám phá phân tích dữ liệu với Python. Pandas DataFrames giúp thao tác dữ liệu của bạn dễ dàng, từ việc chọn hoặc thay thế các cột và chỉ mục để định hình lại dữ liệu của bạnXem ThêmXem ThêmNếu bạn hỏi tôi về khía cạnh dễ bị hiểu lầm nhất của Python, tôi sẽ trả lời mà không cần suy nghĩ kỹ. hệ thống nhập Python. Chỉ cần nhớ bạn đã sử dụng nhập khẩu tương đối bao nhiêu lần và nhận được thứ gì đó như 5; . Mọi lập trình viên Python đều trải qua điều gì đó như thế này và các câu hỏi phổ biến về StackOverflow, chẳng hạn như chúng tôi Nhập tệp từ thư mục khác (1822 phiếu bầu), Nhập tương đối trong Python 3 (1064 phiếu) và Nhập tương đối lần thứ một tỷ (993 phiếu) là một chỉ báo tốt Hệ thống nhập Python không có vẻ phức tạp – nó phức tạp. Vì vậy, mặc dù tài liệu thực sự tốt nhưng nó không cung cấp cho bạn bức tranh toàn cảnh về những gì đang diễn ra. Cách duy nhất để có được một bức tranh như vậy là nghiên cứu điều gì xảy ra đằng sau hậu trường khi Python thực thi một câu lệnh nhập. Và đó là những gì chúng ta sẽ làm ngày hôm nay Ghi chú. Trong bài viết này tôi đang đề cập đến CPython 3. 9. Một số chi tiết triển khai chắc chắn sẽ thay đổi khi CPython phát triển. Tôi sẽ cố gắng theo dõi những thay đổi quan trọng và thêm ghi chú cập nhật Kế hoạch của chúng tôiTrước khi chúng tôi bắt đầu, hãy để tôi trình bày cho bạn một phiên bản chi tiết hơn về kế hoạch của chúng tôi. Đầu tiên, chúng ta sẽ thảo luận về các khái niệm cốt lõi của hệ thống nhập khẩu. mô-đun, mô-đun con, gói, câu lệnh 7, nhập tương đối, v.v. Sau đó, chúng tôi sẽ loại bỏ các câu lệnh nhập khác nhau và thấy rằng cuối cùng tất cả chúng đều gọi hàm 8 tích hợp. Cuối cùng, chúng ta sẽ nghiên cứu cách triển khai mặc định của 8 hoạt động. Đi nàoMô-đun và đối tượng mô-đunHãy xem xét một tuyên bố nhập khẩu đơn giản
Bạn nghĩ nó làm gì? . Và bạn sẽ đúng. Nhưng mô-đun chính xác là gì? . câu lệnh 2 tìm kiếm một mô-đun có tên 0, tạo một đối tượng mô-đun cho mô-đun đó và gán đối tượng mô-đun cho biến. Xem cách chúng tôi phân biệt giữa mô-đun và đối tượng mô-đun. Bây giờ chúng ta có thể định nghĩa các thuật ngữ nàyMô-đun là bất kỳ thứ gì mà Python coi là mô-đun và biết cách tạo đối tượng mô-đun cho. Điều này bao gồm những thứ như tệp Python, thư mục và mô-đun tích hợp được viết bằng C. Chúng ta sẽ xem danh sách đầy đủ trong phần tiếp theo Lý do tại sao chúng tôi nhập bất kỳ mô-đun nào là vì chúng tôi muốn có quyền truy cập vào các hàm, lớp, hằng số và các tên khác mà mô-đun định nghĩa. Những tên này phải được lưu trữ ở đâu đó và đây là đối tượng mô-đun dành cho. Đối tượng mô-đun là một đối tượng Python hoạt động như một không gian tên cho tên của mô-đun. Tên được lưu trữ trong từ điển của đối tượng mô-đun (có sẵn dưới dạng 4), vì vậy chúng tôi có thể truy cập chúng dưới dạng thuộc tínhNếu bạn thắc mắc làm thế nào các đối tượng mô-đun được triển khai, thì đây là định nghĩa từ 5 2Trường 6 lưu trữ từ điển của mô-đun. Các lĩnh vực khác không thực sự quan trọng cho cuộc thảo luận của chúng tôiPython tạo các đối tượng mô-đun ngầm cho chúng ta. Để thấy rằng không có gì kỳ diệu trong quá trình này, chúng ta hãy tự tạo một đối tượng mô-đun. Chúng ta thường tạo các đối tượng Python bằng cách gọi các kiểu của chúng, như 7 hoặc 8. Loại đối tượng mô-đun là 9 trong mã C nhưng nó không có sẵn trong Python dưới dạng tích hợp sẵn. May mắn thay, các loại "không khả dụng" như vậy có thể được tìm thấy trong mô-đun tiêu chuẩn 70 8Mô-đun 70 xác định 72 như thế nào? . Chúng ta cũng có thể làm được 3Cho dù chúng ta có được 72 bằng cách nào, một khi chúng ta có được nó, chúng ta có thể dễ dàng tạo một đối tượng mô-đun 5Một đối tượng mô-đun mới được tạo không thú vị lắm nhưng có một số thuộc tính đặc biệt được khởi tạo trước 6Hầu hết các thuộc tính đặc biệt này chủ yếu được sử dụng bởi chính hệ thống nhập khẩu, nhưng một số cũng được sử dụng trong mã ứng dụng. Ví dụ, thuộc tính 76 thường được sử dụng để lấy tên của mô-đun hiện tại
Lưu ý rằng 76 có sẵn dưới dạng biến toàn cục. Quan sát này có vẻ hiển nhiên, nhưng nó rất quan trọng. Nó xuất phát từ thực tế là từ điển của các biến toàn cục được đặt thành từ điển của mô-đun hiện tại
Mô-đun hiện tại hoạt động như một không gian tên để thực thi mã Python. Khi Python nhập một tệp Python, nó sẽ tạo một đối tượng mô-đun mới và sau đó thực thi nội dung của tệp bằng cách sử dụng từ điển của đối tượng mô-đun làm từ điển của các biến toàn cục. Tương tự, khi Python thực thi trực tiếp một tệp Python, trước tiên, nó tạo một mô-đun đặc biệt có tên là 78 và sau đó sử dụng từ điển của nó làm từ điển của các biến toàn cục. Do đó, các biến toàn cục luôn là thuộc tính của một số mô-đun và mô-đun này được coi là mô-đun hiện tại theo quan điểm của mã thực thiCác loại mô-đun khác nhauTheo mặc định, Python nhận ra những thứ sau đây là mô-đun
Các mô-đun tích hợp là các mô-đun C được biên dịch thành tệp thực thi 31. Vì chúng là một phần của tệp thực thi nên chúng luôn có sẵn. Đây là tính năng chính của họ. Bộ dữ liệu 32 lưu trữ tên của họ 7Các mô-đun bị đóng băng cũng là một phần của tệp thực thi 31, nhưng chúng được viết bằng Python. Mã Python được biên dịch thành một đối tượng mã và sau đó đối tượng mã sắp xếp lại được tích hợp vào tệp thực thi. Các ví dụ về các mô-đun bị đóng băng là 34 và 35. Python đóng băng chúng vì chúng triển khai cốt lõi của hệ thống nhập và do đó, không thể nhập như các tệp Python khácCác tiện ích mở rộng của C hơi giống các mô-đun tích hợp và hơi giống các tệp Python. Một mặt, chúng được viết bằng C hoặc C++ và tương tác với Python thông qua API Python/C. Mặt khác, chúng không phải là một phần của tệp thực thi nhưng được tải động trong quá trình nhập. Một số mô-đun tiêu chuẩn bao gồm 36, 37 và 38 là phần mở rộng của C. Nhiều người khác bao gồm 39, 200 và 201 được viết bằng Python nhưng gọi phần mở rộng C dưới mui xe. Về mặt kỹ thuật, các tiện ích mở rộng C là các thư viện được chia sẻ hiển thị chức năng khởi tạo được gọi là. Chúng thường được đặt tên như 202, nhưng phần mở rộng tệp có thể khác nhau tùy thuộc vào nền tảng. Ví dụ: trên macOS của tôi, bất kỳ tiện ích mở rộng nào trong số này sẽ hoạt động. 203, 204, 205. Và trên Windows, bạn sẽ thấy 206 và các biến thể của nóCác tệp mã byte của Python thường nằm trong thư mục 207 cùng với các tệp Python thông thường. Chúng là kết quả của việc biên dịch mã Python thành bytecode. Cụ thể hơn, tệp 30 chứa một số siêu dữ liệu theo sau là đối tượng mã được sắp xếp theo thứ tự của một mô-đun. Mục đích của nó là giảm thời gian tải của mô-đun bằng cách bỏ qua giai đoạn biên dịch. Khi Python nhập tệp 79, trước tiên, nó sẽ tìm kiếm tệp 30 tương ứng trong thư mục 207 và thực thi nó. Nếu tệp 30 không tồn tại, Python sẽ biên dịch mã và tạo tệpTuy nhiên, chúng tôi sẽ không gọi các mô-đun tệp 30 nếu chúng tôi không thể thực thi và nhập chúng trực tiếp. Ngạc nhiên thay, chúng ta có thể 3Để tìm hiểu thêm về các tệp 30, hãy xem PEP 3147 -- PYC Repository Directories và PEP 552 -- Deterministic pycsNhư chúng ta sẽ thấy sau này, chúng ta có thể tùy chỉnh hệ thống nhập để hỗ trợ nhiều loại mô-đun hơn nữa. Vì vậy, mọi thứ đều có thể được gọi là mô-đun miễn là Python có thể tạo đối tượng mô-đun cho nó với tên mô-đun Mô hình con và góiNếu tên mô-đun được giới hạn ở các mã định danh đơn giản như 215 hoặc 216, thì tất cả chúng phải là duy nhất và chúng tôi sẽ phải suy nghĩ rất nhiều mỗi khi đặt tên cho một tệp mới. Vì lý do này, Python cho phép các mô-đun có các mô-đun con và tên mô-đun chứa dấu chấmKhi Python thực thi câu lệnh này 20đầu tiên nó nhập mô-đun 217 và sau đó là mô-đun con 218. Nó thêm mô-đun con vào từ điển của mô-đun và gán mô-đun cho biến 217, vì vậy chúng ta có thể truy cập mô-đun con dưới dạng thuộc tính của mô-đunMột mô-đun có thể có các mô-đun con được gọi là gói. Về mặt kỹ thuật, một gói là một mô-đun có thuộc tính 220. Thuộc tính này cho Python biết nơi tìm kiếm các mô hình con. Khi Python nhập một mô-đun cấp cao nhất, nó sẽ tìm kiếm mô-đun đó trong các thư mục và kho lưu trữ ZIP được liệt kê trong 6. Nhưng khi nó nhập một mô-đun con, nó sử dụng thuộc tính 220 của mô-đun mẹ thay vì 6gói thông thườngThư mục là cách phổ biến nhất để tổ chức các mô-đun thành các gói. Nếu một thư mục chứa tệp 224, nó được coi là một gói thông thường. Khi Python nhập một thư mục như vậy, nó sẽ thực thi tệp 224, vì vậy các tên được xác định ở đó sẽ trở thành các thuộc tính của mô-đunTệp 224 thường để trống hoặc chứa các thuộc tính liên quan đến gói, chẳng hạn như 227 và 228. Nó cũng có thể được sử dụng để tách API công khai của gói khỏi triển khai nội bộ của gói đó. Giả sử bạn phát triển một thư viện với cấu trúc sau 21Và bạn muốn cung cấp cho người dùng thư viện của mình hai chức năng. 229 được định nghĩa trong 230 và 231 được định nghĩa trong 232. Nếu bạn để trống 224, thì người dùng phải chỉ định các mô-đun con để nhập các chức năng 22Nó có thể là thứ bạn muốn, nhưng bạn cũng có thể muốn cho phép người dùng nhập các chức năng như thế này 23Vì vậy, bạn nhập các chức năng trong 224 24Một thư mục có phần mở rộng C có tên là 235 hoặc có tệp 30 có tên là 237 cũng là một gói thông thường. Python có thể nhập các gói như vậy hoàn toàn tốt 25Gói không gian tênTrước phiên bản 3. 3, Python chỉ có các gói thông thường. Các thư mục không có 224 hoàn toàn không được coi là gói. Và đây là một vấn đề vì mọi người không muốn tạo các tệp 224 trống. PEP 420 khiến các tệp này trở nên không cần thiết bằng cách giới thiệu các gói không gian tên trong Python 3. 3Các gói không gian tên cũng giải quyết một vấn đề khác. Họ cho phép các nhà phát triển đặt nội dung của một gói trên nhiều địa điểm. Ví dụ: nếu bạn có cấu trúc thư mục sau 26Và cả 240 và 241 đều ở trong 6, sau đó bạn có thể nhập cả 243 và 244 như thế này 27Điều này là do 245 là gói không gian tên chứa hai vị trí 28Làm thế nào nó hoạt động? . Nếu sau khi duyệt qua tất cả các mục, nó không thể tìm thấy gói thông thường, tệp Python hoặc phần mở rộng C, nó sẽ tạo một đối tượng mô-đun có 220 chứa các thư mục đã ghi nhớÝ tưởng ban đầu về việc yêu cầu 224 là để ngăn các thư mục có tên như 251 hoặc 252 che khuất các mô-đun tiêu chuẩn. Gói không gian tên không ẩn các mô-đun khác vì chúng có mức độ ưu tiên thấp hơn trong quá trình tìm kiếm mô-đunNhập khẩu từ các mô-đunBên cạnh việc nhập các mô-đun, chúng ta cũng có thể nhập các thuộc tính mô-đun bằng cách sử dụng câu lệnh 7, như vậy 29Câu lệnh này nhập một mô-đun có tên 254 và gán các thuộc tính đã chỉ định cho các biến tương ứng 80Lưu ý biến 254 không có sau khi nhập coi như bị xóa 81Khi Python thấy rằng một mô-đun không có thuộc tính được chỉ định, nó coi thuộc tính đó là một mô-đun con và cố gắng nhập nó. Vì vậy, nếu 254 định nghĩa 257 và 258 nhưng không phải là 259, Python sẽ cố gắng nhập 260Nhập ký tự đại diệnNếu chúng tôi không muốn chỉ định rõ ràng tên để nhập từ một mô-đun, chúng tôi có thể sử dụng hình thức nhập ký tự đại diện 82Tuyên bố này hoạt động như thể 261 đã được thay thế bằng tất cả các tên công khai của mô-đun. Đây là những tên trong từ điển của mô-đun không bắt đầu bằng dấu gạch dưới 262 hoặc tên được liệt kê trong thuộc tính 263 nếu nó được xác địnhNhập khẩu tương đốiCho đến bây giờ, chúng tôi đã nói với Python những mô-đun nào cần nhập bằng cách chỉ định tên mô-đun tuyệt đối. Câu lệnh 7 cũng cho phép chúng tôi chỉ định tên mô-đun tương đối. Đây là vài ví dụ 83Các cấu trúc như 265 và 266 là các tên mô-đun tương đối, nhưng chúng tương đối với cái gì? . Mô-đun hiện tại, giống như bất kỳ mô-đun nào khác, có thể thuộc về một gói. Gói này được gọi là gói hiện tại và đây là tên mô-đun tương đối có liên quan đếnThuộc tính 267 của mô-đun lưu trữ tên của gói mà mô-đun thuộc về. Nếu mô-đun là một gói, thì mô-đun thuộc về chính nó và 267 chỉ là tên của mô-đun ( 76). Nếu mô-đun là mô-đun con, thì nó thuộc về mô-đun chính và 267 được đặt thành tên của mô-đun chính. Cuối cùng, nếu mô-đun không phải là gói cũng không phải là mô-đun con, thì gói của nó không được xác định. Trong trường hợp này, 267 có thể được đặt thành một chuỗi rỗng (e. g. mô-đun là mô-đun cấp cao nhất) hoặc 272 (e. g. mô-đun chạy dưới dạng tập lệnh)Tên mô-đun tương đối là tên mô-đun đứng trước một số dấu chấm. Một dấu chấm hàng đầu đại diện cho gói hiện tại. Vì vậy, khi 267 được xác định, câu lệnh sau 84hoạt động như thể dấu chấm đã được thay thế bằng giá trị của 267Mỗi dấu chấm thừa báo cho Python tăng một cấp từ 267. Nếu 267 được đặt thành 277, thì câu lệnh này 85hoạt động như thể các dấu chấm đã được thay thế bằng 217Bạn không thể di chuyển ra ngoài gói cấp cao nhất. Nếu bạn thử cái này 86Python sẽ báo lỗi 87Điều này là do Python không di chuyển qua hệ thống tệp để giải quyết các lần nhập tương đối. Nó chỉ lấy giá trị của 267, loại bỏ một số hậu tố và thêm một hậu tố mới để có tên mô-đun tuyệt đốiRõ ràng, nhập khẩu tương đối bị phá vỡ khi 267 hoàn toàn không được xác định. Trong trường hợp này, bạn gặp lỗi sau 88Bạn thường thấy nó nhất khi chạy chương trình có nhập tương đối dưới dạng tập lệnh. Vì bạn chỉ định chương trình nào sẽ chạy với đường dẫn hệ thống tệp chứ không phải với tên mô-đun và vì Python cần tên mô-đun để tính toán 267, nên mã được thực thi trong mô-đun 78 có thuộc tính 267 được đặt thành 272Chạy chương trình dưới dạng mô-đunCách tiêu chuẩn để tránh lỗi nhập khi chạy chương trình có nhập tương đối là chạy chương trình dưới dạng mô-đun bằng cách sử dụng công tắc 285 89Công tắc 285 yêu cầu Python sử dụng cùng một cơ chế để tìm mô-đun như trong quá trình nhập. Python lấy tên mô-đun và có thể tính toán gói hiện tại. Ví dụ: nếu chúng tôi chạy mô-đun có tên 287, trong đó 254 đề cập đến tệp 79 thông thường, thì mã sẽ được thực thi trong mô-đun 78 có thuộc tính 267 được đặt thành 292. Bạn có thể đọc thêm về công tắc 285 trong tài liệu và trong PEP 338Ổn thỏa. Đây là một sự khởi động. Bây giờ chúng ta sẽ xem chính xác điều gì sẽ xảy ra khi chúng ta nhập một mô-đun Giảm báo cáo nhập khẩuNếu chúng tôi loại bỏ bất kỳ câu lệnh nhập nào, chúng tôi sẽ thấy rằng cuối cùng nó sẽ gọi hàm 8 tích hợp. Hàm này lấy một tên mô-đun và một loạt các tham số khác, tìm mô-đun và trả về một đối tượng mô-đun cho nó. Ít nhất, đây là những gì nó phải làmPython cho phép chúng tôi đặt 8 thành một chức năng tùy chỉnh, vì vậy chúng tôi có thể thay đổi hoàn toàn quy trình nhập. Ví dụ, đây là một thay đổi phá vỡ mọi thứ 30Bạn hiếm khi thấy mọi người ghi đè 8 vì những lý do khác ngoài ghi nhật ký hoặc gỡ lỗi. Việc triển khai mặc định đã cung cấp các cơ chế mạnh mẽ để tùy chỉnh và chúng tôi sẽ chỉ tập trung vào nóViệc triển khai mặc định của 8 là 298. Vâng, nó gần như đúng. Mô-đun 299 là mô-đun tiêu chuẩn triển khai cốt lõi của hệ thống nhập. Nó được viết bằng Python vì quá trình nhập liên quan đến việc xử lý đường dẫn và những thứ khác mà bạn muốn làm bằng Python hơn là bằng C. Nhưng một số chức năng của 299 được chuyển sang C vì lý do hiệu suất. Và mặc định 8 thực sự gọi một cổng C của 298. Đối với mục đích của chúng tôi, chúng tôi có thể bỏ qua sự khác biệt một cách an toàn và chỉ nghiên cứu phiên bản Python. Trước khi chúng tôi làm điều đó, hãy xem các câu lệnh nhập khác nhau gọi 8 như thế nàoNhập khẩu đơn giảnNhớ lại rằng một đoạn mã Python được thực thi theo hai bước
Để biết chức năng của câu lệnh nhập, chúng ta có thể xem mã byte được tạo cho nó và sau đó tìm hiểu xem mỗi lệnh mã byte thực hiện công việc gì bằng cách xem vòng đánh giá trong 804Để lấy mã byte, chúng tôi sử dụng mô-đun chuẩn 805 31Lệnh 806 đầu tiên đẩy 807 lên ngăn xếp giá trị. 806 thứ hai đẩy 272. Sau đó, lệnh 810 thực hiện điều gì đó mà chúng ta sẽ xem xét ngay sau đây. Cuối cùng, 811 gán giá trị trên cùng của ngăn xếp giá trị cho biến 0Đoạn mã thực thi lệnh 810 như sau 32Tất cả các hành động xảy ra trong hàm 814. Nó gọi 8 để thực hiện công việc, nhưng nếu 8 không bị ghi đè, nó sẽ sử dụng phím tắt và gọi cổng C của 298 được gọi là 818. Đây là cách logic này được triển khai trong mã 33Nếu bạn kiểm tra cẩn thận tất cả những điều trên, bạn sẽ có thể kết luận rằng tuyên bố này
thực sự tương đương với mã này 35ý nghĩa của các đối số theo chuỗi tài liệu của 298 như sau 36Như chúng tôi đã nói, tất cả các câu lệnh nhập cuối cùng đều gọi 8. Họ khác nhau về những gì họ làm trước và sau cuộc gọi và cách họ thực hiện cuộc gọi. Ví dụ: nhập tương đối vượt qua giá trị khác 0 của 821 và câu lệnh 7 vượt qua giá trị không trống của 823Bây giờ hãy biểu diễn các câu lệnh nhập khác qua 8 như chúng ta đã biểu thị 2 nhưng lần này nhanh hơn nhiềuNhập mô-đun contuyên bố này 37biên dịch thành mã byte sau 38và tương đương với đoạn mã sau 39Các đối số của 8 được truyền giống như trong trường hợp của 2. Điểm khác biệt duy nhất là VM gán kết quả của 8 không phải cho tên của mô-đun ( 829 không phải là tên biến hợp lệ) mà cho mã định danh đầu tiên trước dấu chấm, i. e. 217. Như chúng ta sẽ thấy, 8 trả về mô-đun cấp cao nhất trong trường hợp nàytừ nhập khẩutuyên bố này 50biên dịch thành mã byte sau 51và tương đương với đoạn mã sau 52Tên để nhập được thông qua là 823. Khi 823 không trống, 8 không trả về mô-đun cấp cao nhất như trong trường hợp nhập đơn giản mà trả về mô-đun được chỉ định như 218từ nhập *tuyên bố này 53biên dịch thành mã byte sau 54và tương đương với đoạn mã sau 55Thuộc tính 263 liệt kê tất cả các tên công khai của mô-đun. Nếu một số tên được liệt kê trong 263 không được xác định, thì 8 sẽ cố gắng nhập chúng dưới dạng mô hình conNhập khẩu tương đốituyên bố này 56biên dịch thành mã byte sau 57và tương đương với đoạn mã sau 58Đối số 821 cho biết 8 có bao nhiêu dấu chấm hàng đầu mà nhập khẩu tương đối có. Vì nó được đặt thành 841, nên 8 tính toán tên tuyệt đối của mô-đun bằng cách (1) lấy giá trị của 267 và (2) loại bỏ phần cuối cùng của nó. Thuộc tính 267 có sẵn cho 8 vì nó được thông qua với 846Bây giờ chúng ta đã hoàn thành các câu lệnh nhập và chỉ có thể tập trung vào hàm 8Bên trong __import__()Khi tôi học cách chuẩn bị bài viết này, nghiên cứu 8 bằng cách đi theo tất cả các đường dẫn mã của nó không phải là trải nghiệm thú vị nhất. Vì vậy, tôi cung cấp cho bạn một lựa chọn tốt hơn. Tôi sẽ tóm tắt các thuật toán chính của quy trình nhập bằng tiếng Anh đơn giản và cung cấp liên kết đến các chức năng triển khai các thuật toán này để bạn có thể đọc mã nếu có gì đó chưa rõ ràngThuật toán mà 8 thực hiện có thể tóm tắt như sau
Bước 2 là nơi tất cả các hành động xảy ra. Chúng tôi sẽ tập trung vào nó trong các phần còn lại, nhưng trước tiên chúng ta hãy giải thích chi tiết về bước 1 Giải quyết họ hàngĐể giải quyết tên mô-đun tương đối, 8 cần biết gói hiện tại của mô-đun mà từ đó câu lệnh nhập được thực thi. Vì vậy, nó tra cứu 267 trong 861. Nếu 267 là 272, thì 8 sẽ cố gắng suy ra gói hiện tại từ 76. Vì Python luôn đặt chính xác 267 nên dự phòng này thường không cần thiết. Nó chỉ có thể hữu ích cho các mô-đun được tạo bằng các phương tiện khác với cơ chế nhập mặc định. Bạn có thể xem hàm 867 để biết chính xác cách tính gói cước hiện tại. Tất cả những gì chúng ta nên nhớ là quá trình nhập tương đối bị ngắt khi 267 được đặt thành một chuỗi trống, như trong trường hợp mô-đun cấp cao nhất hoặc thành 272, như trong trường hợp tập lệnh và có cơ hội thành công nếu không. Hàm sau đảm bảo điều này 59Sau khi kiểm tra, tên họ hàng được giải quyết 60Và 8 gọi 871 để nhập mô-đunQuy trình nhập khẩuHàm 871 lấy một tên mô-đun tuyệt đối và thực hiện các bước sau
Tất cả các mô-đun đã nhập được lưu trữ trong từ điển 873. Từ điển này ánh xạ tên mô-đun tới các đối tượng mô-đun và hoạt động như một bộ đệm. Trước khi tìm kiếm mô-đun, ________ 1871 kiểm tra ________ 1873 và trả về mô-đun ngay lập tức nếu nó ở đó. Các mô-đun đã nhập được thêm vào 881 ở cuối bước 5Nếu mô-đun không có trong 873, thì 871 sẽ tiếp tục quá trình nhập. Quá trình này bao gồm tìm mô-đun và tải mô-đun. Trình tìm và trình tải là các đối tượng thực hiện các tác vụ nàyTrình tìm và trình tảiCông việc của công cụ tìm là đảm bảo rằng mô-đun tồn tại, xác định trình tải nào sẽ được sử dụng để tải mô-đun và cung cấp thông tin cần thiết để tải, chẳng hạn như vị trí của mô-đun. Công việc của một trình tải là tạo một đối tượng mô-đun cho mô-đun và thực thi mô-đun. Cùng một đối tượng có thể hoạt động như một công cụ tìm và như một trình tải. Một đối tượng như vậy được gọi là một nhà nhập khẩu Trình tìm kiếm triển khai phương thức 884 lấy tên mô-đun và đường dẫn tìm kiếm mô-đun và trả về thông số mô-đun. Thông số mô-đun là một đối tượng đóng gói trình tải và tất cả thông tin cần thiết để tải. Điều này bao gồm các thuộc tính đặc biệt của mô-đun. Chúng được sao chép đơn giản từ thông số kỹ thuật sau khi đối tượng mô-đun được tạo. Ví dụ: 220 được sao chép từ 886 và 267 được sao chép từ 888. Xem tài liệu để biết danh sách đầy đủ các thuộc tính specĐể tìm một thông số kỹ thuật, 871 lặp lại các công cụ tìm được liệt kê trong 890 và gọi 884 trên từng công cụ cho đến khi tìm thấy thông số kỹ thuật. Nếu thông số kỹ thuật không được tìm thấy, 871 tăng 877Theo mặc định, 890 lưu trữ ba công cụ tìm
Chúng được gọi là công cụ tìm đường dẫn meta. Python phân biệt chúng với các công cụ tìm mục nhập đường dẫn là một phần của 897. Chúng ta sẽ thảo luận về cả hai loại công cụ tìm trong các phần tiếp theoSau khi tìm thấy thông số kỹ thuật, 871 lấy trình tải từ thông số kỹ thuật và chuyển thông số kỹ thuật đó sang phương thức 300 của trình tải để tạo một đối tượng mô-đun. Nếu 300 không được triển khai hoặc trả về 272, thì 871 sẽ tự tạo đối tượng mô-đun mới. Nếu đối tượng mô-đun không xác định một số thuộc tính đặc biệt, thường là như vậy, các thuộc tính sẽ được sao chép từ thông số kỹ thuật. Đây là cách logic này được triển khai trong mã 61Sau khi tạo đối tượng mô-đun, 871 thực thi mô-đun bằng cách gọi phương thức 305 của trình tải. Phương thức này làm gì phụ thuộc vào trình tải, nhưng thông thường, nó sẽ đưa vào từ điển của mô-đun các hàm, lớp, hằng số và những thứ khác mà mô-đun định nghĩa. Ví dụ: trình tải tệp Python thực thi nội dung của tệp khi gọi ____ 305Quá trình tải đầy đủ được thực hiện như sau 62Đoạn mã này thú vị vì nhiều lý do. Đầu tiên, một mô-đun được thêm vào 873 trước khi nó được thực thi. Do logic này, Python hỗ trợ nhập vòng tròn. Nếu chúng ta có hai mô-đun nhập lẫn nhau như thế này 63 64Chúng tôi có thể nhập chúng mà không gặp vấn đề gì 65Điều hấp dẫn là mô-đun 217 chỉ được khởi tạo một phần khi mô-đun 309 được thực thi. Vì vậy, nếu chúng ta sử dụng 310 trong 309 66chúng tôi nhận được một lỗi 67Thứ hai, một mô-đun bị xóa khỏi 873 nếu quá trình thực thi không thành công vì bất kỳ lý do gì, nhưng các mô-đun đã được nhập thành công dưới dạng hiệu ứng phụ vẫn còn trong 873Cuối cùng, mô-đun trong 873 có thể được thay thế trong quá trình thực thi mô-đun. Do đó, mô-đun được tra cứu trong 873 trước khi nó được trả lạiBây giờ chúng tôi đã hoàn thành với 871 và 8 và sẵn sàng để xem các công cụ tìm và trình tải khác nhau hoạt động như thế nàoBuildinImporter và FrozenImporterNhư chúng ta có thể đánh giá từ cái tên, 895 vừa là công cụ tìm vừa là trình tải các mô-đun tích hợp. Phương thức 884 của nó kiểm tra xem mô-đun có phải là mô-đun tích hợp hay không và nếu có, sẽ tạo một thông số kỹ thuật không chứa gì ngoài tên của mô-đun và trình tải. Phương thức 300 của nó tìm hàm init của mô-đun và gọi nó. Cả hai phương pháp đều dễ thực hiện vì tên mô-đun tích hợp được ánh xạ tĩnh tới các hàm init 68Các hàm init là các hàm init giống như các phần mở rộng C xác định. Chúng tôi sẽ không thảo luận về cách chúng hoạt động ở đây, vì vậy nếu bạn muốn tìm hiểu thêm về điều này, hãy xem hướng dẫn Mở rộng Python với C hoặc C++ 896 tìm các mô-đun bị đóng băng theo cách tương tự. Tên của chúng được ánh xạ tĩnh tới các đối tượng mã 69Sự khác biệt với 895 là 300 trả về 272. Các đối tượng mã được thực thi bởi 305Bây giờ chúng tôi tập trung vào công cụ tìm đường dẫn meta mà các nhà phát triển ứng dụng nên quan tâm nhất Trình tìm đường dẫn 897 tìm kiếm mô-đun trên đường dẫn tìm kiếm mô-đun. Đường dẫn tìm kiếm mô-đun là 220 của cha mẹ được chuyển dưới dạng đối số 328 thành 884 hoặc 6 nếu đối số này là 272. Nó được mong đợi là một chuỗi có thể lặp lại. Mỗi chuỗi, được gọi là mục nhập đường dẫn, phải chỉ định vị trí để tìm kiếm mô-đun, chẳng hạn như thư mục trên hệ thống tệp 897 không thực sự tự tìm kiếm nhưng liên kết từng mục nhập đường dẫn với một công cụ tìm mục nhập đường dẫn biết cách tìm các mô-đun ở vị trí được chỉ định bởi mục nhập đường dẫn. Để tìm một mô-đun, 897 lặp lại các mục nhập đường dẫn và đối với mỗi mục nhập, hãy gọi 884 của công cụ tìm mục nhập đường dẫn tương ứngĐể biết nên sử dụng công cụ tìm mục nhập đường dẫn nào cho một mục nhập cụ thể, 897 gọi các hook đường dẫn được liệt kê trong 336. Móc đường dẫn là một hàm có thể gọi được lấy mục nhập đường dẫn và trả về công cụ tìm mục nhập đường dẫn. Nó cũng có thể nâng 337, trong trường hợp đó, 897 sẽ thử móc tiếp theo. Để tránh gọi hook trong mỗi lần nhập, 897 lưu trữ các kết quả trong từ điển 340 để ánh xạ các mục nhập đường dẫn tới các công cụ tìm mục nhập đường dẫnTheo mặc định, 336 chứa hai móc đường dẫn
Phiên bản 342 tìm kiếm các mô-đun trong kho lưu trữ ZIP hoặc trong một thư mục bên trong kho lưu trữ ZIP. Nó hỗ trợ các loại mô-đun giống như 343 ngoại trừ phần mở rộng C. Bạn có thể đọc thêm về 342 trong tài liệu và trong PEP 273. Phiên bản 343 tìm kiếm các mô-đun trong một thư mục. Chúng ta sẽ thảo luận về nó trong phần tiếp theoBên cạnh việc gọi các công cụ tìm mục nhập đường dẫn, 897 tạo thông số kỹ thuật cho các gói không gian tên. Khi một công cụ tìm mục nhập đường dẫn trả về một thông số không chỉ định trình tải, điều này có nghĩa là thông số đó mô tả một phần của gói không gian tên (thường chỉ là một thư mục). Trong trường hợp này, 897 nhớ thuộc tính 350 của thông số kỹ thuật này và tiếp tục với mục nhập đường dẫn tiếp theo với hy vọng rằng nó sẽ tìm thấy tệp Python, gói thông thường hoặc tiện ích mở rộng C. Nếu cuối cùng nó không tìm thấy bất kỳ phần nào trong số này, thì nó sẽ tạo một thông số kỹ thuật mới cho gói không gian tên có 350 chứa tất cả các phần đã ghi nhớTóm lại những gì chúng ta đã nói về 897, đây là thuật toán hoàn chỉnh mà 884 của nó thực hiện
Tất cả logic phức tạp này của 897 hầu như không cần thiết. Thông thường, một mục nhập đường dẫn chỉ là một đường dẫn đến một thư mục, vì vậy, 897 gọi phương thức 884 của một thể hiện 343 được trả về bởi hook tương ứngTrình tìm tệpPhiên bản 343 tìm kiếm các mô-đun trong thư mục được chỉ định bởi mục nhập đường dẫn. Mục nhập đường dẫn có thể là đường dẫn tuyệt đối hoặc đường dẫn tương đối. Trong trường hợp sau, nó được giải quyết đối với thư mục làm việc hiện tạiPhương pháp 884 của 343 lấy tên mô-đun tuyệt đối nhưng chỉ cần phần "đuôi" sau dấu chấm cuối cùng vì phần gói đã được sử dụng để xác định thư mục cần tìm trong. Nó trích xuất "đuôi" như thế này 0Sau đó, nó thực hiện tìm kiếm. Nó tìm kiếm một thư mục có tên là 382 chứa 224, 237 hoặc 385 với một số phần mở rộng tệp thư viện được chia sẻ như 205. Nó cũng tìm các tệp có tên 387, 388 và 389. Nếu nó tìm thấy bất kỳ thứ nào trong số này, nó sẽ tạo một thông số kỹ thuật với trình tải tương ứng
Nếu nó tìm thấy một thư mục không phải là gói thông thường, nó sẽ tạo một thông số kỹ thuật với bộ tải được đặt thành 272. 897 thu thập một thông số gói không gian tên duy nhất từ các thông số kỹ thuật đóThuật toán mà 884 thực hiện có thể được tóm tắt như sau
Một thông số gói thông thường được tạo như thế này 1một thông số tập tin như thế này 2và một gói không gian tên như thế này 3Khi thông số kỹ thuật được tạo, quá trình tải mô-đun bắt đầu. 390 đáng để nghiên cứu, nhưng chúng ta nên để dành nó cho một bài viết khác về tiện ích mở rộng C. 393 cũng không thú vị lắm nên cũng không bàn nữa. 391 phù hợp nhất với chúng tôi vì nó tải các tệp 79. Chúng tôi sẽ đề cập ngắn gọn về cách thức hoạt động của nóNguồnFileLoaderPhương thức 300 của 391 luôn trả về 272. Điều này có nghĩa là 871 tự tạo đối tượng mô-đun mới và khởi tạo nó bằng cách sao chép các thuộc tính từ thông số kỹ thuậtPhương pháp 305 của 391 thực hiện chính xác những gì bạn mong đợi 4Nó gọi 516 để tạo một đối tượng mã từ tệp và sau đó gọi 517 để thực thi đối tượng mã trong không gian tên của mô-đun. Lưu ý rằng trước tiên, 516 sẽ cố đọc mã byte từ tệp 30 trong thư mục 207 và tạo tệp này nếu nó chưa tồn tạiĐó là nó. Chúng tôi đã hoàn thành nghiên cứu của mình về công cụ tìm và trình tải và xem điều gì xảy ra trong quá trình nhập. Hãy tóm tắt những gì chúng ta đã học Tóm tắt quy trình nhập khẩuBất kỳ câu lệnh nhập nào cũng biên dịch thành một loạt hướng dẫn mã byte, một trong số đó, được gọi là 810, nhập mô-đun bằng cách gọi hàm 8 tích hợp. Nếu mô-đun được chỉ định bằng tên tương đối, trước tiên, 8 sẽ phân giải tên tương đối thành tên tuyệt đối bằng cách sử dụng thuộc tính 267 của mô-đun hiện tại. Sau đó, nó tra cứu mô-đun trong 873 và trả về mô-đun nếu nó ở đó. Nếu mô-đun không có ở đó, 8 sẽ cố gắng tìm thông số kỹ thuật của mô-đun. Nó gọi phương thức 884 của mọi công cụ tìm được liệt kê trong 890 cho đến khi một số công cụ tìm trả về thông số kỹ thuật. Nếu mô-đun là mô-đun tích hợp, 895 trả về thông số kỹ thuật. Nếu mô-đun là mô-đun bị đóng băng, 896 trả về thông số kỹ thuật. Mặt khác, 897 tìm kiếm mô-đun trên đường dẫn tìm kiếm mô-đun, đó là thuộc tính 220 của mô-đun chính hoặc 6 nếu cái trước không được xác định. 897 lặp lại các mục nhập đường dẫn và, đối với mỗi mục nhập, gọi phương thức 884 của công cụ tìm mục nhập đường dẫn tương ứng. Để có công cụ tìm mục nhập đường dẫn tương ứng, 897 chuyển mục nhập đường dẫn tới các nội dung có thể gọi được liệt kê trong 336. Nếu mục nhập đường dẫn là một đường dẫn đến một thư mục, thì một trong các hàm có thể gọi được sẽ trả về một phiên bản 343 để tìm kiếm các mô-đun trong thư mục đó. 897 gọi nó là 884. Phương pháp 884 của 343 kiểm tra xem thư mục được chỉ định bởi mục nhập đường dẫn có chứa phần mở rộng C, tệp 79, tệp 30 hoặc thư mục có tên khớp với tên mô-đun hay không. Nếu nó tìm thấy bất cứ thứ gì, nó sẽ tạo một thông số kỹ thuật mô-đun với trình tải tương ứng. Khi 8 nhận thông số kỹ thuật, nó gọi phương thức 300 của trình tải để tạo một đối tượng mô-đun và sau đó gọi phương thức 305 để thực thi mô-đun. Cuối cùng, nó đặt mô-đun vào 873 và trả về mô-đunBạn còn câu hỏi nào không? Có gì trong hệ thống. con đường?Theo mặc định, 6 bao gồm những điều sau đây
Để xây dựng các đường dẫn này, trước tiên Python xác định vị trí của tệp thực thi 31. Nếu chúng ta chạy tệp thực thi bằng cách chỉ định một đường dẫn, Python đã biết vị trí. Nếu không, nó sẽ tìm kiếm tệp thực thi trong 563. Cuối cùng, nó nhận được một cái gì đó như 564. Sau đó, nó cố gắng tìm ra vị trí của các mô-đun tiêu chuẩn. Nó di chuyển một thư mục lên từ tệp thực thi cho đến khi tìm thấy tệp 565. Tệp này biểu thị thư mục chứa các mô-đun chuẩn được viết bằng Python. Quá trình tương tự được lặp lại để tìm thư mục chứa các phần mở rộng C tiêu chuẩn, nhưng thư mục 566 được sử dụng làm điểm đánh dấu lần này. Tệp 567 cùng với tệp thực thi hoặc một thư mục phía trên có thể chỉ định một thư mục khác để bắt đầu tìm kiếm từ đó. Và biến môi trường 568 có thể được sử dụng để chỉ định thư mục "cơ sở" để Python hoàn toàn không cần thực hiện tìm kiếmMô-đun tiêu chuẩn 252 lấy thư mục "cơ sở" được tìm thấy trong quá trình tìm kiếm hoặc được chỉ định bởi 568 và thêm 571 vào thư mục đó để lấy thư mục chứa các mô-đun của bên thứ ba. Thư mục này có thể chứa các tệp cấu hình đường dẫn 572 yêu cầu 252 thêm các thư mục dành riêng cho trang web vào 6. Các thư mục được thêm vào cũng có thể chứa các tệp 572 để quá trình lặp lại theo cách đệ quyNếu tệp 567 tồn tại, thì 252 sử dụng thư mục chứa tệp này làm thư mục "cơ sở". Lưu ý rằng đây không phải là thư mục mà 567 chỉ định. Theo cơ chế này, Python hỗ trợ các môi trường ảo có các thư mục dành riêng cho trang web nhưng chia sẻ thư viện chuẩn với cài đặt toàn hệ thống. Kiểm tra các tài liệu trên 252 và PEP 405 - Môi trường ảo Python để tìm hiểu thêm về điều nàyQuá trình tính toán 6 thậm chí còn phức tạp hơn. Nếu bạn muốn biết những sắc thái đó, hãy xem câu trả lời StackOverflow nàyPhần kết luậnNếu bạn hỏi tôi về khía cạnh dễ bị hiểu lầm nhất của Python, tôi sẽ trả lời mà không cần suy nghĩ kỹ. hệ thống nhập Python. Cho đến khi tôi viết bài này, tôi thực sự không thể nói chính xác mô-đun là gì; . Tôi có thể nói gì bây giờ? . Tôi đổ lỗi cho sự hiểu lầm của mình về các tài liệu đã đơn giản hóa thực tế như thế này
hoặc bỏ qua các chi tiết như thế này
Nhập khẩu tương đối thực sự không trực quan, nhưng một khi bạn hiểu rằng chúng chỉ là một cách để chỉ định tên mô-đun liên quan đến tên gói hiện tại, bạn sẽ không gặp vấn đề gì với chúng Công cụ tìm đường dẫn meta, công cụ tìm mục nhập đường dẫn, móc đường dẫn, mục nhập đường dẫn và trình tải làm cho hệ thống nhập phức tạp hơn nhưng cũng làm cho nó linh hoạt hơn. PEP 302 và PEP 451 đưa ra một số lý do cho sự đánh đổi này Còn về 6 thì sao? . Có lẽ, nó quá phức tạp để mô tả chính xác. Nhưng tôi nghĩ rằng giá trị gần đúng như giá trị chúng tôi đưa ra trong phần trước là đủ tốt cho các mục đích thực tếNhìn chung, nghiên cứu hệ thống nhập khẩu là hữu ích, nhưng tôi nghĩ rằng lần sau chúng ta nên nghiên cứu một cái gì đó thú vị hơn. Làm thế nào về không đồng bộ/chờ đợi? Nếu bạn có bất kỳ câu hỏi, nhận xét hoặc đề xuất nào, vui lòng liên hệ với tôi theo địa chỉ victor@tenthousandmeters. com Python tìm hàng nhập khẩu ở đâu?Trình thông dịch python cố tìm thư mục chứa mô-đun mà chúng tôi đang cố gắng nhập vào sys. đường dẫn . Đó là danh sách các thư mục mà Python sẽ tìm kiếm sau khi tìm kiếm xong các mô-đun được lưu trong bộ nhớ cache và các mô-đun thư viện chuẩn của Python.
Điều gì xảy ra khi nhập Python?Khi mô-đun được nhập lần đầu tiên, Python tìm kiếm mô-đun và nếu tìm thấy, nó sẽ tạo một đối tượng mô-đun 1, khởi tạo nó . Nếu không tìm thấy mô-đun được đặt tên, Lỗi ModuleNotFoundError sẽ xuất hiện. Python thực hiện các chiến lược khác nhau để tìm kiếm mô-đun được đặt tên khi máy móc nhập khẩu được gọi.
Các thư viện Python được lưu trữ ở đâu?Thông thường, thư viện Python nằm trong thư mục site-packages trong thư mục cài đặt Python , tuy nhiên, nếu nó không nằm trong thư mục .
Đường dẫn nhập trong Python là gì?Đây là cách dễ nhất để nhập mô-đun Python bằng cách thêm đường dẫn mô-đun vào biến đường dẫn . Biến đường dẫn chứa các thư mục Trình thông dịch Python tìm kiếm các mô-đun đã được nhập trong tệp nguồn. cú pháp. hệ thống. con đường. chắp thêm("module_path") |