Mô-đun Src Python

Chương 3. cung cấp một cái nhìn tổng quan thực tế về cách tạo, cài đặt và phân phối gói Python. Chương này bây giờ đi vào chi tiết hơn về gói Python thực sự là gì, tìm hiểu sâu hơn về cách các gói được cấu trúc, cài đặt và phân phối

Chúng tôi bắt đầu thảo luận về cách các mô-đun và gói được trình bày trong Python và tại sao chúng được sử dụng. Sau đó, chúng tôi thảo luận về một số chủ đề cấu trúc gói nâng cao hơn, chẳng hạn như kiểm soát hành vi nhập của gói và bao gồm các tệp không phải mã, như dữ liệu. Chương này kết thúc với phần thảo luận về phân phối gói là gì, cách xây dựng chúng và cách chúng được cài đặt. Đồng thời, chúng tôi sẽ trình bày các khái niệm chính bằng cách tiếp tục phát triển gói

import greetings
type[greetings]
9 của chúng tôi từ chương trước

4. 1. Nguyên tắc cơ bản về đóng gói

Chúng ta sẽ bắt đầu chương này bằng cách khám phá một số chi tiết triển khai cấp thấp hơn liên quan đến gói là gì, cách chúng được cấu trúc và cách chúng được sử dụng trong Python

Tất cả dữ liệu trong chương trình Python được biểu diễn bằng đối tượng hoặc bằng quan hệ giữa các đối tượng. Ví dụ: số nguyên và hàm là các loại đối tượng Python. Chúng ta có thể tìm loại đối tượng Python bằng hàm

module
0. Ví dụ: mã bên dưới, chạy trong trình thông dịch Python, tạo đối tượng số nguyên và đối tượng hàm được ánh xạ tới tên lần lượt là
module
1 và
module
2

a = 1
type[a]

int

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]

function

Đối tượng Python quan trọng đối với cuộc thảo luận của chúng ta về các gói là đối tượng “mô-đun”. Mô-đun là một đối tượng đóng vai trò là đơn vị tổ chức của mã Python. Thông thường, mã Python bạn muốn sử dụng lại được lưu trữ trong một tệp có phần. py và được nhập bằng cách sử dụng câu lệnh

module
3. Quá trình này tạo một đối tượng mô-đun có cùng tên với tệp đã nhập [không bao gồm. py] và từ đối tượng này, chúng ta có thể truy cập nội dung của tệp

Ví dụ, hãy tưởng tượng chúng ta có một mô-đun

module
4 trong thư mục hiện tại có chứa các chức năng để in “Xin chào thế giới. ” bằng tiếng Anh và tiếng Squamish [người Squamish là người bản địa của British Columbia, Canada ngày nay]

module
0

Chúng tôi có thể nhập mô-đun đó bằng cách sử dụng câu lệnh

module
3 và có thể sử dụng hàm
module
0 để xác minh rằng chúng tôi đã tạo một đối tượng mô-đun, đối tượng này đã được ánh xạ tới tên “lời chào” [tên của tệp]

import greetings
type[greetings]

module

Chúng tôi gọi đối tượng mô-đun là “đơn vị mã tổ chức” vì nội dung của mô-đun [trong trường hợp này là hai chức năng “hello world”] có thể được truy cập thông qua tên mô-đun và “ký hiệu dấu chấm”. Ví dụ

module
5

module
6

module
7

int
0

Tại thời điểm này trong cuộc thảo luận của chúng ta, thật hữu ích khi đề cập đến các không gian tên của Python. Một “không gian tên” trong Python là ánh xạ từ tên đến đối tượng. Từ các ví dụ mã ở trên, chúng tôi đã thêm các tên

module
1 [một số nguyên],
module
2 [một hàm] và
module
9 [một mô-đun] vào không gian tên hiện tại và có thể sử dụng các tên đó để chỉ các đối tượng mà chúng tôi đã tạo. Hàm
module
50 có thể được sử dụng để kiểm tra một không gian tên. Khi được gọi mà không có đối số,
module
50 trả về danh sách các tên được xác định trong không gian tên hiện tại

int
1

int
2

Trong kết quả ở trên, chúng ta có thể thấy tên của ba đối tượng chúng ta đã xác định trong phần này.

module
1,
module
2 và
module
9. Các tên khác được giới hạn bởi hai dấu gạch dưới là các đối tượng được khởi tạo tự động khi chúng tôi khởi động trình thông dịch Python và là các chi tiết triển khai không quan trọng đối với cuộc thảo luận của chúng tôi ở đây nhưng có thể đọc được trong Python

Không gian tên được tạo tại các thời điểm khác nhau, có thời gian tồn tại khác nhau và có thể được truy cập từ các phần khác nhau của chương trình Python — nhưng những chi tiết này lạc đề khỏi cuộc thảo luận của chúng tôi và chúng tôi hướng người đọc quan tâm đến Python để tìm hiểu thêm. Điểm quan trọng cần làm ở đây là khi một mô-đun được nhập bằng cách sử dụng câu lệnh

module
3, một đối tượng mô-đun được tạo và nó có không gian tên riêng chứa tên của các đối tượng Python được xác định trong các mô-đun. Ví dụ: khi chúng tôi nhập tệp
module
4 trước đó, chúng tôi đã tạo một đối tượng mô-đun
module
9 và không gian tên chứa tên của các đối tượng được xác định trong tệp —
module
2 và
module
59 — mà chúng tôi có thể truy cập bằng cách sử dụng ký hiệu dấu chấm, e. g. ,
module
60 và
module
61

Theo cách này, đối tượng mô-đun cô lập một bộ sưu tập mã và cung cấp cho chúng ta một cách rõ ràng, hợp lý và có tổ chức để truy cập nó. Chúng ta có thể kiểm tra không gian tên của một mô-đun bằng cách chuyển đối tượng mô-đun làm đầu vào cho hàm

module
50

int
3

int
4

Một điểm quan trọng cần nhấn mạnh ở đây là không có mối quan hệ nào giữa các tên trong các không gian tên khác nhau. Điều đó có nghĩa là chúng ta có thể có các đối tượng có cùng tên trong phiên Python nếu chúng tồn tại trong các không gian tên khác nhau. Ví dụ: trong phiên Python mà chúng tôi đã chạy trong phần này, chúng tôi có quyền truy cập vào hai hàm

module
2; . Mặc dù các chức năng này có cùng tên, nhưng không có mối quan hệ nào giữa chúng vì chúng tồn tại trong các không gian tên khác nhau; . Vì vậy, chúng ta có thể truy cập cả hai với cú pháp thích hợp

int
5

int
6

module
5

module
6

Bây giờ chúng ta đã có hiểu biết cơ bản về các mô-đun, chúng ta có thể thảo luận thêm về các gói. Các gói chỉ là một tập hợp của một hoặc nhiều mô-đun. Chúng thường được cấu trúc như một thư mục [gói] chứa một hoặc nhiều. py [mô-đun] và/hoặc thư mục con [mà chúng tôi gọi là gói con]. Một tệp đặc biệt có tên

module
68 được sử dụng để nói với Python rằng một thư mục là một gói [chứ không phải chỉ là một thư mục cũ đơn giản trên máy tính của bạn]. Chúng ta sẽ nói nhiều hơn về cấu trúc gói và tệp
module
68 trong phần , nhưng bây giờ, đây là một ví dụ về cấu trúc gói đơn giản với hai mô-đun và một gói con

int
9

Nói một cách đơn giản, các gói cung cấp một mức độ trừu tượng khác cho mã của chúng tôi và cho phép chúng tôi tổ chức các mô-đun liên quan trong một không gian tên gói duy nhất. Thật hữu ích khi nghĩ về một gói như một mô-đun chứa các mô-đun khác. Trên thực tế, đây gần như là cách Python xử lý các gói. Bất kể bạn có

module
3 một mô-đun độc lập hay không [i. e. , một. py] hoặc một gói [i. e. , một thư mục], Python sẽ tạo một đối tượng mô-đun trong không gian tên hiện tại. Ví dụ: hãy nhập gói
import greetings
type[greetings]
9 mà chúng ta đã tạo trong Chương 3. và kiểm tra loại của nó [hãy nhớ rằng gói này chứa hai mô-đun;
module
72 và
module
73]

Chú ý

Nếu bạn đang theo dõi từ Chương 3. và tạo một môi trường ảo cho gói

import greetings
type[greetings]
9 của bạn bằng cách sử dụng
module
75, như chúng tôi đã làm trong , hãy đảm bảo kích hoạt môi trường đó trước khi tiếp tục với chương này bằng cách chạy
module
76 tại dòng lệnh

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
0

module

Lưu ý rằng mặc dù đã nhập gói

import greetings
type[greetings]
9 của chúng tôi [chứa hai mô-đun], Python vẫn tạo một đối tượng mô-đun duy nhất. Cũng giống như trước đây, chúng tôi có thể truy cập nội dung của gói thông qua ký hiệu dấu chấm. Ví dụ: chúng ta có thể nhập hàm
module
78 từ mô-đun
module
79 của gói
import greetings
type[greetings]
9 bằng cú pháp sau

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
2

function

Trong khi chúng tôi nhận được một đối tượng mô-đun bất kể chúng tôi có nhập một mô-đun đơn lẻ hay không [một. py] hoặc một gói [một thư mục chứa một hoặc nhiều. py], một điểm khác biệt về kỹ thuật giữa mô-đun và gói trong Python là các gói được nhập dưới dạng đối tượng mô-đun có thuộc tính

int
01

Khi nhập một gói hoặc mô-đun, Python sẽ tìm kiếm nó trong danh sách thư mục mặc định được xác định trong

int
02

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
4

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
5

Ghi chú

Danh sách các thư mục được hiển thị bởi

int
02 sẽ thay đổi tùy thuộc vào cách bạn cài đặt Python và bạn có đang ở trong môi trường ảo hay không. Chuỗi trống ở đầu danh sách đại diện cho thư mục hiện tại

Nhưng khi nhập nội dung nào đó từ gói, Python sử dụng thuộc tính

int
01 của gói để tìm nội dung đó, thay vì các đường dẫn trong
int
02. Ví dụ: hãy kiểm tra thuộc tính
int
01 của đối tượng
import greetings
type[greetings]
9

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
6

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
7

Chú ý

Trong phần chúng ta đã thảo luận về cách

int
08, công cụ mà chúng ta đang sử dụng để phát triển gói
import greetings
type[greetings]
9, cài đặt các gói ở chế độ "có thể chỉnh sửa" nghĩa là nó cài đặt một liên kết tới mã của gói trên máy tính của bạn và đó là những gì chúng ta thấy trong kết quả ở trên. Nếu bạn cài đặt
import greetings
type[greetings]
9 [hoặc bất kỳ gói nào khác] bằng cách sử dụng
int
11 hoặc
int
12 và kiểm tra thuộc tính
int
01 của nó, bạn sẽ thấy một đường dẫn bao gồm thư mục
int
14, đây là nơi Python đặt các gói đã cài đặt theo mặc định, e. g.
int
15

Chúng ta sẽ nói nhiều hơn về cài đặt gói trong

Tất cả điều này có nghĩa là khi bạn nhập

int
16, trước tiên Python sẽ tìm kiếm một mô-đun hoặc gói có tên là
import greetings
type[greetings]
9 trong danh sách các đường dẫn tìm kiếm được xác định bởi
int
02. Nếu
import greetings
type[greetings]
9 là một gói, thì nó sẽ tìm kiếm mô-đun hoặc gói con
module
79 bằng cách sử dụng
int
21 làm đường dẫn tìm kiếm [chứ không phải
int
02]. Tại thời điểm này, chúng ta đang đi sâu vào các sắc thái của hệ thống nhập của Python và lạc đề khỏi phạm vi của cuốn sách này, nhưng những độc giả quan tâm có thể đọc thêm về hệ thống nhập của Python trong tài liệu Python

Cuối cùng, thông điệp rút ra quan trọng từ phần này là các gói là một tập hợp các mô-đun Python. Chúng giúp chúng tôi tổ chức và truy cập mã của mình tốt hơn, cũng như phân phối mã đó cho những người khác, như chúng tôi sẽ thảo luận trong

4. 2. Cấu trúc gói

Với lý thuyết đã được loại bỏ, bây giờ chúng ta sẽ quay lại với các chủ đề thực tế hơn trong phần này;

4. 2. 1. Nội dung gói

Như chúng ta đã thảo luận trong phần trước, các gói là một cách tổ chức và truy cập một tập hợp các mô-đun. Về cơ bản, một gói được xác định là một thư mục chứa tệp

module
68 và một mô-đun là một tệp có. phần mở rộng py có chứa mã Python. Dưới đây là cấu trúc thư mục ví dụ của gói Python đơn giản với hai mô-đun và gói con

int
9

module
68 yêu cầu Python coi một thư mục là một gói [hoặc gói con]. Các tệp
module
68 thường trống, nhưng chúng cũng có thể chứa mã khởi tạo hữu ích để chạy khi gói của bạn được nhập, như chúng ta sẽ thảo luận trong

Cấu trúc trên đáp ứng các tiêu chí cho gói Python và bạn có thể

module
3 nội dung từ gói này trên máy tính cục bộ của mình nếu nó nằm trong thư mục làm việc hiện tại [hoặc nếu đường dẫn của nó đã được thêm thủ công vào
int
02]. Nhưng gói này thiếu nội dung cần thiết để có thể cài đặt được

Để tạo một gói có thể cài đặt, chúng tôi cần một công cụ có khả năng cài đặt và xây dựng các gói. Hiện tại, các công cụ phổ biến nhất được sử dụng để phát triển gói là

int
08,
int
30 và
int
31. Trong cuốn sách này, chúng tôi sử dụng
int
08, nhưng chúng tôi sẽ so sánh các công cụ này sau trong. Bất kể công cụ bạn sử dụng là gì, nó sẽ dựa trên [các] tệp cấu hình xác định siêu dữ liệu và hướng dẫn cài đặt cho gói của bạn. Trong một dự án do
int
08 quản lý, tệp đó là
int
34. Bạn cũng nên đưa README vào thư mục gốc của gói để cung cấp thông tin cấp cao về gói và đặt mã Python của gói vào thư mục
int
35 [chúng ta sẽ thảo luận lý do tại sao lại có trong thư mục này]. Vì vậy, cấu trúc cho một gói có thể cài đặt trông giống như thế này

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
9

Cấu trúc trên phù hợp với một gói đơn giản hoặc một gói chỉ dành cho mục đích sử dụng cá nhân. Nhưng hầu hết các gói bao gồm nhiều chuông và còi hơn thế này, chẳng hạn như tài liệu chi tiết, bài kiểm tra, v.v., như chúng ta đã thấy trong Chương 3. . Gói

import greetings
type[greetings]
9 mà chúng tôi đã tạo trong chương đó là một ví dụ điển hình hơn về cấu trúc gói Python

function
0

Không phải tất cả nội dung này sẽ được bao gồm trong phiên bản gói mà bạn cài đặt hoặc phân phối cho người khác. Thông thường, chỉ có mã Python [trong thư mục

int
35] tạo thành phiên bản có thể cài đặt của gói của bạn [nhưng chúng tôi sẽ chỉ ra cách bạn có thể chỉ định nội dung bổ sung để đưa vào ]. Phần nội dung còn lại, chẳng hạn như tài liệu và kiểm tra, tồn tại để hỗ trợ phát triển và người dùng gói của bạn không cần đến nội dung này, do đó, nội dung này thường được chia sẻ [nếu muốn] qua một phương tiện cộng tác như GitHub, nơi các nhà phát triển khác có thể truy cập và

Ghi chú

Cấu trúc gói được mô tả trong phần này về mặt kỹ thuật được gọi là “gói thông thường” trong Python và đó là cấu trúc mà phần lớn các gói Python và nhà phát triển sử dụng. Tuy nhiên, Python cũng hỗ trợ một loại gói thứ hai được gọi là “gói không gian tên”. Các gói không gian tên là một cách để phân tách một gói Python duy nhất trên nhiều thư mục. Không giống như các gói thông thường, nơi tất cả nội dung nằm trong cùng một hệ thống phân cấp thư mục, các gói không gian tên có thể được hình thành từ các thư mục ở các vị trí khác nhau trên hệ thống tệp và không chứa tệp

module
68

Lý do chính mà nhà phát triển có thể muốn sử dụng gói không gian tên là nếu họ muốn phát triển, cài đặt và phân phối các phần của gói một cách riêng biệt hoặc nếu họ muốn kết hợp các gói nằm trên các vị trí khác nhau trên hệ thống tệp của họ. Tuy nhiên, các gói không gian tên có thể là một chủ đề khó hiểu đối với người mới bắt đầu và phần lớn các nhà phát triển sẽ không bao giờ tạo gói không gian tên nên chúng tôi sẽ không thảo luận thêm về chúng trong cuốn sách này. Thay vào đó, chúng tôi giới thiệu những độc giả quan tâm đến việc tìm hiểu thêm về PEP 420 và Python. Do đó, khi chúng tôi sử dụng thuật ngữ “gói” trong cuốn sách này, chúng tôi muốn nói cụ thể là “gói thông thường”

4. 2. 2. Tên gói và mô-đun

Khi xây dựng một gói, điều quan trọng là chọn tên thích hợp cho gói của bạn và các mô-đun của nó. Quy ước và nguyên tắc đặt tên gói Python được mô tả trong Đề xuất cải tiến Python [PEP] 8 và PEP 423. Các hướng dẫn cơ bản là

  • Các gói và mô-đun phải có một tên duy nhất, ngắn gọn, toàn chữ thường

  • Dấu gạch dưới có thể được sử dụng để phân tách các từ trong tên nếu nó cải thiện khả năng đọc, nhưng việc sử dụng chúng thường không được khuyến khích

Về tên thực tế được chọn cho một mô-đun hoặc gói, có thể hữu ích khi xem xét “ba chữ M” sau đây

  1. ý nghĩa. tên phải phản ánh chức năng của gói

  2. Đáng nhớ. tên phải dễ dàng cho người dùng tìm, ghi nhớ và liên quan đến các gói có liên quan khác

  3. quản lý được. hãy nhớ rằng người dùng gói của bạn sẽ truy cập nội dung/không gian tên của nó thông qua ký hiệu dấu chấm. Làm cho họ làm điều này nhanh chóng và dễ dàng nhất có thể bằng cách giữ cho tên của bạn ngắn gọn và ngọt ngào. Ví dụ: hãy tưởng tượng nếu chúng ta gọi gói

    import greetings
    type[greetings]
    
    9 của mình là
    int
    
    40. Mỗi khi người dùng muốn truy cập hàm ________ 178 từ mô-đun ________ 179, họ phải viết cái này.
    int
    
    43 — thật tuyệt

Cuối cùng, bạn phải luôn kiểm tra PyPI và các trang lưu trữ phổ biến khác như GitHub, GitLab, BitBucket, v.v. , để đảm bảo rằng tên gói bạn chọn chưa được sử dụng

Hình. 4. 1 Giữ tên gói có ý nghĩa, dễ nhớ và dễ quản lý.

4. 2. 3. Tham chiếu trong gói

Khi xây dựng các gói gồm nhiều mô-đun, người ta thường muốn sử dụng mã từ mô-đun này sang mô-đun khác. Ví dụ: xem xét cấu trúc gói sau

function
1

Nhà phát triển có thể muốn nhập mã từ

int
44 vào
int
45. Đây là "tham chiếu trong gói" và có thể được thực hiện thông qua nhập "tuyệt đối" hoặc "tương đối"

Nhập tuyệt đối sử dụng tên gói trong ngữ cảnh tuyệt đối. Nhập khẩu tương đối sử dụng dấu chấm để chỉ ra nơi bắt đầu nhập khẩu tương đối. Một dấu chấm duy nhất biểu thị một lần nhập so với gói hiện tại [hoặc gói phụ], các dấu chấm bổ sung có thể được sử dụng để di chuyển xa hơn lên hệ thống phân cấp đóng gói, một cấp cho mỗi dấu chấm sau dấu chấm đầu tiên

hiển thị một số ví dụ thực tế về nhập khẩu tuyệt đối và tương đối, dựa trên cấu trúc gói được hiển thị trước đó

Bảng 4. 1 Thể hiện nhập nội gói tuyệt đối và tương đối.

tuyệt đối

Liên quan đến

Nhập từ

int
44 trong
int
45

int
48

int
49

Nhập từ

int
44 trong
int
51

int
48

int
53

Nhập từ

int
51 trong
int
44

int
56

int
57

Mặc dù lựa chọn ở đây chủ yếu tùy thuộc vào sở thích cá nhân, PEP 8 khuyên bạn nên sử dụng nhập khẩu tuyệt đối vì chúng rõ ràng

4. 2. 4. Tệp init

Trước đó chúng ta đã thảo luận về cách sử dụng tệp

module
68 để nói với Python rằng thư mục chứa tệp
module
68 là một gói. Tệp
module
68 có thể và thường được để trống và chỉ được sử dụng cho mục đích xác định thư mục dưới dạng gói. Tuy nhiên, nó cũng có thể được sử dụng để thêm các đối tượng vào không gian tên của gói, cung cấp tài liệu và/hoặc chạy mã khởi tạo khác

Chúng tôi sẽ chứng minh chức năng này bằng cách sử dụng gói

import greetings
type[greetings]
9 mà chúng tôi đã phát triển trong Chương 3. . Hãy xem xét
module
68 của gói hàng của chúng tôi

function
2

Khi một gói được nhập, tệp

module
68 được thực thi và bất kỳ đối tượng nào mà nó xác định đều được liên kết với không gian tên của gói. Ví dụ: trong gói Python, quy ước xác định phiên bản của gói ở hai vị trí

  1. Trong tệp cấu hình của gói,

    int
    
    34, như chúng ta đã thấy trong

  2. Trong tệp

    module
    
    68 của gói sử dụng thuộc tính
    int
    
    66 để người dùng có thể nhanh chóng kiểm tra phiên bản gói của bạn mà họ đang sử dụng, với mã như

function
3

function
4

Đôi khi, bạn sẽ thấy số phiên bản được mã hóa cứng trong tệp

module
68, chẳng hạn như
int
68. Nhưng điều này có nghĩa là bạn phải nhớ cập nhật phiên bản ở hai nơi bất cứ lúc nào bạn muốn tạo phiên bản mới cho gói của mình —
module
68 và
int
34 [chúng ta sẽ thảo luận về việc tạo phiên bản trong Chương 7. ]. Thay vào đó, tốt hơn là bạn chỉ nên xác định phiên bản gói của mình trong
int
34, sau đó đọc theo chương trình trong tệp
module
68 bằng cách sử dụng hàm
int
73, hàm đọc phiên bản của gói từ siêu dữ liệu đã cài đặt của nó [i. e. , tệp
int
34]

int
75 mà chúng tôi đã sử dụng để tạo gói
import greetings
type[greetings]
9 [] đã điền mã này vào tệp
module
68 của chúng tôi

function
5

Bởi vì bất kỳ đối tượng nào được xác định trong

module
68 đều bị ràng buộc với không gian tên của gói trên
module
3, nên biến
int
66 có thể truy cập được từ không gian tên của gói của chúng tôi như chúng ta đã thấy trước đó

Một trường hợp sử dụng phổ biến khác của tệp

module
68 là kiểm soát hành vi nhập gói. Ví dụ: hiện tại chỉ có hai chức năng chính mà người dùng sẽ sử dụng phổ biến từ gói
import greetings
type[greetings]
9 của chúng tôi.
int
83 và
int
84. Người dùng phải nhập đường dẫn đầy đủ đến các chức năng này để nhập chúng

function
6

Chúng tôi có thể làm cho cuộc sống của người dùng dễ dàng hơn bằng cách nhập các hàm cốt lõi này vào tệp

module
68 của
import greetings
type[greetings]
9, tệp này sẽ liên kết chúng với không gian tên gói. Ví dụ: mã bên dưới, được thêm vào tệp
module
68, nhập các chức năng cốt lõi của chúng tôi
int
83 và
int
84

function
7

Chú ý

Nếu bạn đang theo dõi và phát triển gói

import greetings
type[greetings]
9 trong cuốn sách này và đã thử cài đặt gói đó từ TestPyPI hoặc PyPI trong , gói đó sẽ không còn được cài đặt ở “chế độ có thể chỉnh sửa” và do đó sẽ không phản ánh bất kỳ thay đổi nào bạn thực hiện đối với mã nguồn. Bạn sẽ phải chạy
int
91 để xem các thay đổi của mình và đưa gói của bạn trở lại chế độ có thể chỉnh sửa [là chế độ bạn muốn phát triển]

Các chức năng hiện được liên kết với không gian tên

import greetings
type[greetings]
9, vì vậy người dùng có thể truy cập chúng như thế này

function
8

function
9

Cuối cùng, tệp

module
68 có thể được sử dụng để tùy chỉnh cách gói của bạn và nội dung của gói được nhập. Đây là một bài tập thú vị khi truy cập các gói Python lớn, chẳng hạn như NumPy, pandas và scikit learn, để xem các loại mã khởi tạo mà chúng chạy trong các tệp ________ 168 của chúng

4. 2. 5. Bao gồm các tệp không phải mã trong một gói

Xem xét lại cấu trúc đầy đủ của gói

import greetings
type[greetings]
9 của chúng tôi

module
00

Phiên bản có thể cài đặt của gói mà bạn phân phối cho người khác thường sẽ chỉ chứa mã Python trong thư mục

int
35. Phần còn lại của nội dung tồn tại để hỗ trợ phát triển gói và người dùng không cần thiết để thực sự sử dụng gói. Nội dung này thường được nhà phát triển chia sẻ bằng một số phương tiện khác, chẳng hạn như GitHub, để các nhà phát triển khác có thể truy cập và đóng góp cho nội dung đó nếu họ muốn

Tuy nhiên, có thể bao gồm nội dung bổ sung tùy ý trong gói của bạn sẽ được người dùng cài đặt, cùng với mã Python thông thường. Phương pháp thực hiện việc này khác nhau tùy thuộc vào công cụ đóng gói bạn đang sử dụng, nhưng với

int
08, bạn có thể chỉ định nội dung bổ sung mà bạn muốn đưa vào gói của mình bằng cách sử dụng tham số
int
98 trong bảng
int
99 trong
int
34. Ví dụ: nếu chúng tôi muốn đưa thư mục
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
01 và tệp
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
02 vào bản phân phối gói có thể cài đặt của mình, chúng tôi sẽ thêm phần sau vào
int
34

module
01

Hầu hết các nhà phát triển sẽ không gửi nội dung bổ sung cùng với gói của họ như thế này, mà thích chia sẻ nội dung đó qua một dịch vụ như GitHub, nhưng chắc chắn có những trường hợp sử dụng để làm như vậy — ví dụ: nếu bạn đang chia sẻ riêng một gói trong một tổ chức, bạn . ]

4. 2. 6. Bao gồm dữ liệu trong một gói

Một loại phi mã mà các nhà phát triển thường muốn đưa vào một gói là dữ liệu. Có một số lý do khiến nhà phát triển có thể muốn đưa dữ liệu vào gói của họ

  1. Bắt buộc phải sử dụng một số chức năng của gói

  2. Để cung cấp dữ liệu ví dụ để giúp chứng minh chức năng của gói

  3. Là một phương pháp phân phối và phiên bản [các] tệp dữ liệu

  4. Nếu gói đang được sử dụng để kết hợp phân tích dữ liệu có thể lặp lại và điều quan trọng là phải giữ mã và dữ liệu cùng nhau

Bất kể trường hợp sử dụng nào, có hai cách điển hình để đưa dữ liệu vào gói Python

  1. Bao gồm dữ liệu thô như một phần của gói có thể cài đặt và cung cấp mã để giúp người dùng tải dữ liệu đó [nếu được yêu cầu]. Tùy chọn này rất phù hợp với các tệp dữ liệu nhỏ hơn hoặc cho dữ liệu mà gói hoàn toàn phụ thuộc vào

  2. Bao gồm các tập lệnh như một phần của gói tải xuống dữ liệu từ nguồn bên ngoài. Tùy chọn này phù hợp với các tệp dữ liệu lớn hoặc những tệp mà người dùng có thể chỉ cần tùy chọn

Chúng tôi sẽ trình bày tùy chọn 1 ở trên bằng một ví dụ. Gói

import greetings
type[greetings]
9 của chúng tôi giúp người dùng tính toán số từ trong tệp văn bản. Để chứng minh chức năng của gói của chúng tôi cho người dùng mới, có thể hữu ích khi thêm tệp văn bản mẫu vào gói của chúng tôi để họ thực hành với. Đối với gói của chúng tôi, chúng tôi sẽ thêm một tệp văn bản của tiểu thuyết Flatland, của Edwin Abbott [có sẵn trực tuyến].

Để đưa dữ liệu này vào gói của chúng tôi, chúng tôi cần thực hiện hai việc

  1. Bao gồm phần thô. txt trong gói của chúng tôi

  2. Bao gồm mã để giúp người dùng truy cập dữ liệu

Chúng tôi sẽ bắt đầu bằng cách tạo một gói con

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
05 mới trong thư mục
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
06 của chúng tôi, nơi bạn nên tải xuống và đặt tiểu thuyết Flatland được liên kết dưới dạng
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
07. Chúng tôi cũng sẽ tạo một mô-đun mới
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
08 trong gói của mình, mô-đun này sẽ sớm điền mã để giúp người dùng tải dữ liệu. Cấu trúc thư mục
import greetings
type[greetings]
9 của chúng ta bây giờ trông như thế này

module
02

Bây giờ chúng ta cần thêm một số mã Python vào

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
08 để giúp người dùng tải dữ liệu mẫu. Cách được khuyến nghị để truy cập các tệp dữ liệu trong gói là sử dụng
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
11. Chức năng chính của gói
import greetings
type[greetings]
9 của chúng tôi,
int
83 yêu cầu người dùng chuyển đường dẫn tệp đến tệp văn bản mà họ muốn đếm từ trong. Vì vậy, chúng ta nên viết một hàm trong
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
08 mới của mình để trả về đường dẫn đến tệp
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
07 ví dụ cho người dùng. Hàm
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
16 có thể giúp chúng ta làm điều đó. Bạn có thể đọc về chức năng này trong Python; . Đoạn mã bên dưới, mà chúng tôi sẽ thêm vào
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
08, thể hiện cách sử dụng của nó

module
03

Khi bạn đã thêm mã này vào

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
08, bạn có thể dùng thử

module
04

module
05

Chú ý

Nếu bạn đang theo dõi và phát triển gói

import greetings
type[greetings]
9 trong cuốn sách này và đã thử cài đặt gói đó từ TestPyPI hoặc PyPI trong , gói đó sẽ không còn được cài đặt ở “chế độ có thể chỉnh sửa” và do đó sẽ không phản ánh bất kỳ thay đổi nào bạn thực hiện đối với mã nguồn. Bạn sẽ phải chạy
int
91 để xem các thay đổi của mình và đưa gói của bạn trở lại chế độ có thể chỉnh sửa [là chế độ bạn muốn phát triển]

Người dùng có thể sử dụng trực tiếp đường dẫn này trong hàm

import greetings
type[greetings]
9
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
25 như sau

module
06

module
07

Đây chỉ là một ví dụ về cách chúng tôi có thể đưa dữ liệu vào gói của mình và hiển thị dữ liệu cho người dùng. Mô-đun

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
11 có thể được sử dụng để tải bất kỳ loại dữ liệu nào theo nhiều cách khác nhau [dưới dạng đường dẫn, dưới dạng chuỗi, dưới dạng tệp nhị phân, v.v. ]. Nếu bạn đang phát triển một gói bao gồm dữ liệu hướng tới người dùng, chúng tôi khuyên bạn nên xem qua
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
11 , cũng như các mô-đun “bộ dữ liệu” có trong các thư viện Python lớn hơn như scikit-learning, torchvision hoặc statsmodels để tìm hiểu thêm

4. 2. 7. Bố cục nguồn

Khi mô tả và xác định cấu trúc gói xuyên suốt cuốn sách này, chúng tôi đã lồng mã Python của gói bên trong thư mục

int
35, như trong cấu trúc ví dụ bên dưới. Bố cục này được gọi là bố cục “src”/”nguồn” vì những lý do rõ ràng

module
08

Tuy nhiên, việc lồng mã gói vào thư mục

int
35 là không bắt buộc để xây dựng gói và cũng thường thấy các gói không có mã đó. Chúng tôi sẽ gọi đây là bố cục “không phải src” và hiển thị một ví dụ bên dưới

module
09

Nói chung, chúng tôi khuyên bạn nên sử dụng bố cục “src” thay vì bố cục “không phải src” [và Cơ quan đóng gói Python cũng vậy] vì nó có một số lợi thế khi phát triển và phân phối các gói Python có thể cài đặt. Chúng tôi liệt kê một vài trong số này dưới đây

  1. Đối với các nhà phát triển sử dụng khung thử nghiệm như

    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    30, bố cục “src” buộc bạn phải cài đặt gói của mình trước khi có thể thử nghiệm. Hầu hết các nhà phát triển sẽ đồng ý rằng bạn muốn kiểm tra gói của mình vì nó sẽ được cài đặt bởi người dùng, thay vì gói hiện đang tồn tại trên máy của bạn. Vấn đề với bố cục “không phải src” là Python có thể
    module
    
    3 gói của bạn ngay cả khi nó chưa được cài đặt. Điều này là do trong hầu hết các trường hợp, vị trí đầu tiên Python tìm kiếm khi chạy
    module
    
    3 là thư mục hiện tại [hãy kiểm tra điều này bằng cách nhập ________ 633 và chạy ________ 634]. Nếu không có thư mục “src”, Python sẽ tìm thấy gói của bạn như nó tồn tại trong thư mục hiện tại và nhập nó, thay vì sử dụng nó như nó sẽ được cài đặt trên máy của người dùng. Có rất nhiều câu chuyện kinh dị về việc các nhà phát triển tải các bản phân phối bị hỏng lên PyPI vì họ đang kiểm tra mã của họ khi nó tồn tại trên máy của họ chứ không phải do người dùng cài đặt. Vấn đề này được mô tả chi tiết trong Ionel Cristian Mărieș’ Đóng gói Thư viện Python và Thử nghiệm và Đóng gói các bài đăng trên blog tuyệt vời của Hynek Schlawack dành cho những người quan tâm

  2. Bố cục “src” dẫn đến các bản cài đặt có thể chỉnh sửa gọn gàng hơn cho gói của bạn. Nhớ lại điều đó khi phát triển một gói, thông thường cài đặt nó ở chế độ có thể chỉnh sửa [mặc định khi chạy

    int
    
    91]. Điều này thêm đường dẫn đến mã Python của dự án của bạn vào danh sách
    int
    
    02 để các thay đổi đối với mã nguồn của bạn có sẵn ngay lập tức khi bạn
    module
    
    3 mà không cần phải cài đặt lại. Với bố cục “src”, đường dẫn đó trông giống như thế này

    import greetings
    type[greetings]
    
    0

    Ngược lại, bố cục “không phải src” sẽ thêm gốc dự án của bạn vào

    int
    
    02 [không có thư mục “src” để cung cấp lớp phân tách]

    import greetings
    type[greetings]
    
    1

    Thường có nhiều thứ hơn là mã Python ở đường dẫn đó. Có thể có các mô-đun thử nghiệm, mã cào, tệp dữ liệu, tài liệu, tập lệnh mẫu, v.v. , tất cả đều có khả năng nhập được trong quy trình phát triển của bạn

  3. Cuối cùng, “src” nói chung là một vị trí mã nguồn được công nhận rộng rãi, giúp người khác dễ dàng điều hướng nhanh nội dung trong gói của bạn

Cuối cùng, mặc dù bạn chắc chắn có thể sử dụng “bố cục không phải src” để phát triển gói, nhưng việc sử dụng bố cục “src” thường sẽ giảm khả năng mọi thứ bị hỏng trong quá trình phát triển và phân phối

4. 3. Phân phối và cài đặt gói

Trong phần này, chúng tôi sẽ không viết bất kỳ mã nào, mà chúng tôi sẽ thảo luận về lý thuyết liên quan đến phân phối và cài đặt gói cho những ai quan tâm. Nếu đó không phải là bạn, vui lòng bỏ qua

Như chúng ta đã thấy trong Chương 3. , quy trình làm việc điển hình để phát triển và phân phối gói Python như sau

  1. Nhà phát triển tạo gói Python trên máy của họ

  2. Nhà phát triển sử dụng một công cụ như

    int
    
    08 để xây dựng bản phân phối từ gói đó

  3. Nhà phát triển chia sẻ bản phân phối, thường bằng cách tải lên kho lưu trữ trực tuyến như PyPI

  4. Người dùng sử dụng công cụ cài đặt như

    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    40 để tải xuống bản phân phối và cài đặt nó trên máy của họ

  5. [Tùy chọn] Người dùng cung cấp phản hồi cho nhà phát triển về gói [xác định lỗi, yêu cầu tính năng, v.v. ] và chu kỳ lặp lại

Quy trình công việc này được minh họa trong

Hình. 4. 2 Chu kỳ gói Python.

Để xây dựng trực giác về các bước trong quy trình này, chúng tôi sẽ bắt đầu ở cuối người dùng và thảo luận về cách các gói được cài đặt. Sau đó, chúng ta sẽ tìm hiểu ngược lại để hiểu rõ hơn về bản phân phối và cách chúng được tạo ra

4. 3. 1. Cài đặt gói

Để được cài đặt, một gói cần tạo hai thư mục

  1. def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    41. một thư mục chứa các tệp nguồn của gói [tôi. e. , mô-đun và gói con]

  2. def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    42. một thư mục chứa các tệp chứa thông tin về gói, chẳng hạn như tệp siêu dữ liệu có thông tin như tác giả của gói và phiên bản Python nào nó hỗ trợ [METADATA], tệp giấy phép [LICENSE], tệp chỉ định công cụ nào đã được sử dụng để cài đặt . Các tệp này được mô tả chi tiết trong

Chúng ta sẽ nói về cách các thư mục này thực sự được xây dựng trong thời gian ngắn, còn bây giờ, chúng ta sẽ nói về cài đặt. Khi bạn cài đặt một gói có trình cài đặt như

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
40, các thư mục trên được sao chép vào thư mục
int
14 của bản cài đặt Python của bạn, đây là một trong những vị trí mặc định mà Python tìm khi nhập gói. Đường dẫn chính xác đến thư mục
int
14 khác nhau tùy thuộc vào hệ điều hành của bạn, cách bạn cài đặt Python và liệu bạn có đang sử dụng môi trường ảo hay không. Bạn có thể kiểm tra đường dẫn bằng biến
int
02. Các đường dẫn bên dưới dành cho MacOS, với Python được cài đặt qua Miniconda và với một môi trường ảo có tên là
import greetings
type[greetings]
9 được kích hoạt

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
4

import greetings
type[greetings]
3

Nếu bạn điều hướng đến thư mục

int
14, bạn sẽ thấy các ví dụ về thư mục
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
41 và
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
42 cho mỗi gói bạn đã cài đặt. Ví dụ: nếu chúng tôi
int
11 gói
import greetings
type[greetings]
9 mà chúng tôi đã tải lên PyPI vào năm , chúng tôi sẽ thấy phần sau trong thư mục
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
53 của chúng tôi

import greetings
type[greetings]
4

import greetings
type[greetings]
5

Vì vậy, câu hỏi là, làm thế nào để chúng tôi cung cấp các thư mục

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
41 và
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
42 cần thiết để cài đặt gói của chúng tôi?

  1. Tạo một kho lưu trữ duy nhất chứa tất cả mã nguồn gói, siêu dữ liệu và hướng dẫn về cách tạo thư mục

    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    41 và
    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    42, sau đó chia sẻ kho lưu trữ đó với người dùng. Điều này được gọi là phân phối nguồn hoặc sdist. Để cài đặt gói của bạn từ một sdist, người dùng cần tải xuống kho lưu trữ, giải nén và sử dụng các hướng dẫn bản dựng đi kèm để cài đặt nó vào các thư mục
    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    41 và
    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    42 trên máy tính của họ [chúng ta sẽ nói về cách “xây dựng” các thư mục này . Cuối cùng, gói được cài đặt bằng cách sao chép các thư mục này vào thư mục
    int
    
    14

  2. Xây dựng các thư mục

    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    41 và
    def hello_world[name]:
            print[f"Hello world! My name is {name}."]
    type[hello_world]
    
    42 trên máy của chúng tôi, nén chúng thành một tệp duy nhất và chia sẻ chúng với người dùng. Tập tin duy nhất này được gọi là một bánh xe. Người dùng chỉ cần tải xuống bánh xe và giải nén nội dung vào thư mục
    int
    
    14;

int
11 có thể xử lý cài đặt từ sdist hoặc bánh xe, nhưng việc phân phối gói của bạn cho người dùng dưới dạng bánh xe [tùy chọn 2] chắc chắn có vẻ thích hợp hơn; . Đây là lý do tại sao bánh xe là định dạng phân phối ưa thích cho các gói Python. Thực ra khi bạn chạy
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
65 thì nó sẽ luôn ưu tiên cài gói chỉ định từ bánh xe [nếu có]

Tại thời điểm này, bạn có thể tự hỏi tại sao chúng ta lại bận tâm với sdists. Lý do là bánh xe không phải lúc nào cũng có sẵn cho người dùng. Một số gói Python chứa “phần mở rộng” được viết bằng các ngôn ngữ khác, chẳng hạn như C/C++, vì chúng cung cấp các cải tiến về chức năng và hiệu suất. Mặc dù Python thường được gọi là ngôn ngữ thông dịch [tôi. e. , mã Python của bạn được dịch sang mã máy khi nó được thực thi], các ngôn ngữ như C/C++ yêu cầu biên dịch bởi một chương trình biên dịch trước khi chúng có thể được sử dụng [i. e. , mã của bạn phải được dịch sang “mã máy” trước khi có thể thực thi]. Quá trình biên dịch dành riêng cho nền tảng. Do đó, nếu nhà phát triển muốn cung cấp bánh xe của một gói bao gồm các tiện ích mở rộng bằng ngôn ngữ khác, họ sẽ phải tạo một bánh xe cho mỗi nền tảng mà họ muốn hỗ trợ [e. g. , MacOS-arm64, MacOS-x86, Win-32, Win-amd64, v.v. ]. Vì lý do này, sdist thường được trang bị bánh xe;

Ví dụ: gói

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
66 phổ biến chứa các tiện ích mở rộng được viết bằng C, vì vậy bánh xe của nó dành riêng cho nền tảng. Các bánh xe có một quy ước đặt tên cụ thể [được mô tả trong PEP 427], bao gồm tên của nền tảng mà chúng hỗ trợ;

Bánh xe dành riêng cho một nền tảng được gọi là "bánh xe nền tảng". Tuy nhiên, phần lớn các gói Python sử dụng mã Python thuần túy [i. e. , chúng không bao gồm các tiện ích mở rộng được viết bằng các ngôn ngữ khác] và do đó, không cần phải lo lắng về việc tạo bánh xe nền tảng. Hầu hết các nhà phát triển và độc giả của cuốn sách này sẽ chỉ tạo ra một bánh xe cho gói của họ. một “bánh xe vạn năng” [tương thích với Python 2 và 3] hoặc một “bánh xe Python thuần túy” [tương thích với Python 2 hoặc 3]. Công cụ xây dựng mà bạn sử dụng để tạo bản phân phối của mình sẽ xử lý việc tạo bánh xe cho bạn [như chúng ta sẽ nói trong phần tiếp theo], vì vậy bạn không cần phải lo lắng về điều đó, nhưng thật thú vị khi biết những điều này

4. 3. 2. Xây dựng sdists và bánh xe

Trong phần trước, chúng ta đã nói về cách các gói cần tạo thư mục

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
41 và
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
42 để được cài đặt và cách bánh xe là một kho lưu trữ duy nhất chứa các tệp này. Vì vậy, làm thế nào chính xác để chúng ta xây dựng một bánh xe?

Tóm lại, quá trình xây dựng bao gồm

  1. Nhà phát triển xây dựng nguồn gói thành một sdist{phân phối. sdists};

  2. Nhà phát triển hoặc người dùng tạo bánh xe từ sdist;

  3. Người dùng cài đặt bánh xe{phân phối. bánh xe}

Các bước xây dựng ở đây là nơi các công cụ đóng gói như

int
08,
int
30 hoặc
int
31 xuất hiện. Những công cụ này cung cấp mã cần thiết để xây dựng sdist và bánh xe. Nhớ lại tệp
int
34 mà
int
08 sử dụng để quản lý phát triển gói. Một bảng trong tệp đó mà chúng tôi không nói đến khi giới thiệu tệp trong đó là
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
75

import greetings
type[greetings]
6

Bảng này chỉ định các công cụ cần thiết để xây dựng sdist và bánh xe cho một gói [

def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
76] và nơi các hàm thực sự thực hiện việc xây dựng được đặt trong thư viện của công cụ xây dựng [
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
77]. Ví dụ: bảng trên cho thấy thư viện
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
78 được yêu cầu để xây dựng gói của chúng tôi và các chức năng xây dựng được đặt trong
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
79. Nếu bạn xem mã nguồn của mô-đun
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
79 của
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
78, bạn sẽ thấy các chức năng như
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
82 và
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
83. Cơ chế xây dựng chính xác nằm ngoài phạm vi của cuốn sách này, vì vậy chúng tôi sẽ không đi vào chi tiết về cách chúng hoạt động. Tuy nhiên, với tư cách là một cuốn sách về đóng gói, sẽ là thiếu sót nếu không đề cập đến khả năng chỉ định các công cụ xây dựng cần thiết để tạo các sdist và bánh xe của một gói là một bước phát triển tương đối mới trong hệ sinh thái đóng gói. Chức năng này đã được giới thiệu trong PEP 517 và PEP 518, để loại bỏ sự phụ thuộc của hệ thống đóng gói vào các công cụ cũ. Các PEP này là một tài liệu thú vị dành cho những ai muốn tìm hiểu sâu hơn về các chi tiết cấp thấp của việc xây dựng và cài đặt các bản phân phối gói

4. 3. 3. Công cụ đóng gói

Trọng tâm của cuốn sách này là về quy trình công việc và các công cụ giúp cho việc đóng gói trở nên dễ tiếp cận và hiệu quả.

int
08 là một trong những công cụ đó; .
int
08 được định cấu hình hoàn toàn bằng một tệp
int
34 duy nhất và có các lệnh trực quan để cài đặt gói [
int
91], quản lý các phần phụ thuộc [
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
88], xây dựng bản phân phối [
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
89] và xuất bản các bản phân phối đó lên kho lưu trữ như PyPI [
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
90]

Một công cụ đóng gói hiện đại thay thế là

int
30.
int
30 về cơ bản là phiên bản rút gọn của
int
08. Nó cũng được quản lý bởi tệp
int
34 và cung cấp các lệnh tương tự như
int
08 để giúp cài đặt gói [
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
96], xây dựng bản phân phối [
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
97] và xuất bản các bản phân phối đó lên kho lưu trữ như PyPI [
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
98]. Sự khác biệt chính giữa
int
30 và
int
08 là
int
30 không tự động quản lý các thành phần phụ thuộc trong dự án của bạn như
int
08; . Do đó, chúng tôi thích
int
08 hơn vì điều đó có nghĩa là có ít điều phải lo lắng hơn

Nhược điểm của

int
08 và
int
30 là tại thời điểm viết bài này, chúng chỉ hỗ trợ các gói thuần Python chứ không hỗ trợ các gói chứa các phần mở rộng được viết bằng các ngôn ngữ khác mà chúng ta đã thảo luận trong. Điều này hoàn toàn tốt cho đại đa số các nhà phát triển. Tuy nhiên, đối với những người muốn xây dựng các gói nâng cao hơn bao gồm mã không phải Python, thì
int
31 là tùy chọn ưu tiên. Trong một thời gian dài,
int
31 là công cụ xây dựng mặc định cho các gói Python nên nó vẫn được sử dụng bởi nhiều dự án đã tồn tại được một thời gian.
int
31 yêu cầu chuyên môn cao hơn một chút để định cấu hình so với
int
08 hoặc
int
30, bạn có thể đọc thêm về điều này trong tài liệu, vì vậy chúng tôi ưu tiên sử dụng
int
08 hoặc
int
30 cho các dự án đóng gói nếu có thể

4. 3. 4. Kho gói

Trong Chương 3. , chúng tôi đã phát hành gói

import greetings
type[greetings]
9 của mình cho Chỉ mục gói Python [PyPI] và thảo luận về cách PyPI là kho lưu trữ chính cho các gói Python. Ngay cả khi bạn chưa bao giờ nghe nói về PyPI, nếu bạn đã từng chạy
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
65 thì bạn đã cài đặt các gói từ đó. Nếu bạn quan tâm đến việc chia sẻ công khai tác phẩm của mình, PyPI có thể là nơi bạn sẽ phát hành gói của mình, tuy nhiên, đó không phải là lựa chọn duy nhất

Kho lưu trữ Anaconda và conda-forge là kho phần mềm phổ biến tiếp theo cho các gói Python. Các gói trên các kho lưu trữ này có thể được cài đặt từ dòng lệnh bằng cách sử dụng

int
12 [chúng tôi đã cài đặt công cụ
module
75 trong ]. Sự khác biệt chính giữa PyPI và các kho lưu trữ này là chúng có thể lưu trữ phần mềm không phải Python [trái ngược với PyPI chỉ lưu trữ phần mềm Python] và các gói
module
75 là các tệp nhị phân [không bao giờ cần phải xây dựng gói hoặc phần phụ thuộc của nó từ . Do đó, các gói phụ thuộc vào mã không phải Python thường được phát hành cho Anaconda hoặc conda-forge. Ngay cả đối với các gói thuần Python, đôi khi các nhà phát triển vẫn tạo gói
module
75 và tải lên Anaconda hoặc conda-forge để phục vụ cho người dùng đang sử dụng
module
75 làm trình quản lý gói thay vì
def hello_world[name]:
        print[f"Hello world! My name is {name}."]
type[hello_world]
40. Đối với những người quan tâm, Anaconda cung cấp một hướng dẫn hữu ích để giúp chuyển đổi các gói trên PyPI thành gói
module
75, nhưng đối với hầu hết người đọc cuốn sách này, việc xây dựng các bản phân phối sdist và bánh xe và chia sẻ chúng trên PyPI là đủ

Trong một số trường hợp, bạn có thể muốn phát hành gói của mình vào kho lưu trữ riêng [ví dụ: chỉ dành cho công ty của bạn sử dụng nội bộ]. Có nhiều tùy chọn kho lưu trữ riêng cho các gói Python. Các công ty như Anaconda, PyDist và GemFury đều là những ví dụ cung cấp dịch vụ lưu trữ gói Python riêng [thường phải trả phí]. Bạn cũng có thể thiết lập máy chủ của riêng mình trên một máy chuyên dụng hoặc dịch vụ đám mây — như đã thảo luận trong bài viết này. Bạn cũng có thể chọn lưu trữ gói của mình trên GitHub [hoặc tương đương] và bỏ qua việc phát hành tới kho lưu trữ phần mềm chuyên dụng.

int
11 hỗ trợ cài đặt gói trực tiếp từ kho lưu trữ GitHub mà bạn có quyền truy cập, như đã thảo luận trong tài liệu. Bạn có thể
int
11 từ nhánh kho lưu trữ, cam kết cụ thể hoặc thẻ. Ví dụ: chúng tôi đã gắn thẻ bản phát hành v0. 1. 0 của gói
import greetings
type[greetings]
9 của chúng tôi trên GitHub trong. Những người khác hiện có thể cài đặt gói của chúng tôi trực tiếp từ GitHub bằng lệnh sau

import greetings
type[greetings]
7

Cài đặt từ GitHub có thể hữu ích cho những người dùng muốn phiên bản gói của bạn chưa có trên PyPI [ví dụ: phiên bản phát triển] hoặc nếu bạn muốn lưu trữ gói của mình trong kho lưu trữ riêng và chỉ chia sẻ gói đó với một số cộng tác viên được chọn. Tuy nhiên, nói chung, chúng tôi không khuyến nghị GitHub chia sẻ các gói Python cho nhiều đối tượng vì đại đa số người dùng Python không cài đặt các gói từ GitHub và các kho lưu trữ phần mềm chuyên dụng như PyPI cung cấp khả năng khám phá tốt hơn, dễ cài đặt và dấu ấn của

4. 4. Kiểm soát phiên bản

Trong đó, chúng tôi đã thực hiện một thay đổi quan trọng đối với gói

import greetings
type[greetings]
9 của mình bằng cách thêm mô-đun
function
27 mới và một số dữ liệu mẫu. Chúng tôi sẽ phát hành gói mới trong Chương 7. bao gồm sự thay đổi này. Vì vậy, nếu bạn đang tự mình xây dựng gói
import greetings
type[greetings]
9 và sử dụng kiểm soát phiên bản, hãy chuyển giao những thay đổi này cho kho lưu trữ cục bộ và từ xa của bạn bằng cách sử dụng các lệnh bên dưới. Nếu bạn không xây dựng gói
import greetings
type[greetings]
9 hoặc không sử dụng kiểm soát phiên bản, bạn có thể chuyển sang chương tiếp theo

Mô-đun SRC trong Python là gì?

src/ — Đây là thư mục chứa mã gói python của bạn . Cấu trúc của thư mục này thay đổi tùy theo bố cục ứng dụng bạn đã chọn. logs/ — tệp nhật ký được lưu trong thư mục này.

Làm cách nào để cài đặt mô-đun trong Python?

Cài đặt mô-đun bằng pip .
Đảm bảo mô-đun pip đã được cài đặt. .
Xác minh việc phát hành pip để đảm bảo nó được cài đặt chính xác. .
Install the new Python module using the command pip install . .. .
Để liệt kê tất cả các gói và mô-đun Python đã cài đặt, hãy sử dụng lệnh danh sách pip

Làm cách nào để cài đặt pip cho Python?

Chạy python get-pip. p . 2 Điều này sẽ cài đặt hoặc nâng cấp pip. Ngoài ra, nó sẽ cài đặt các công cụ thiết lập và bánh xe nếu chúng chưa được cài đặt. Hãy thận trọng nếu bạn đang sử dụng bản cài đặt Python do hệ điều hành của bạn hoặc trình quản lý gói khác quản lý.

Làm cách nào để cài đặt pip trong Python Mac?

Để cài đặt PIP bằng ensurepip. Mở ứng dụng Mac Terminal qua Launchpad. Trong Terminal, gõ python -m ensurepip hoặc python3 -m ensurepip rồi nhấn Enter. Nếu thiếu PIP, ensurepip sẽ cài đặt PIP. Thực hiện theo bất kỳ hướng dẫn bổ sung nào trên màn hình để hoàn tất quy trình này.

Chủ Đề