Mô-đun (và gói) là một cách tuyệt vời của Pythonic để chia chương trình của bạn thành các không gian tên riêng biệt, đây dường như là một mục tiêu ngầm của câu hỏi này. Thật vậy, khi tôi đang học những kiến thức cơ bản về Python, tôi cảm thấy thất vọng vì thiếu tính năng phạm vi khối. Tuy nhiên, một khi tôi hiểu các mô-đun Python, tôi có thể thực hiện các mục tiêu trước đây của mình một cách thanh lịch hơn mà không cần đến phạm vi khối.
Với vai trò là động lực và để hướng mọi người đi đúng hướng, tôi nghĩ sẽ hữu ích khi đưa ra các ví dụ rõ ràng về một số cấu trúc phạm vi của Python. Đầu tiên, tôi giải thích nỗ lực thất bại của mình trong việc sử dụng các lớp Python để triển khai phạm vi khối. Tiếp theo, tôi giải thích cách tôi đạt được điều gì đó hữu ích hơn bằng cách sử dụng các mô-đun Python. Ở phần cuối, tôi phác thảo một ứng dụng thực tế của các gói để tải và lọc dữ liệu.
Đang thử phạm vi khối với các lớp
Trong một vài khoảnh khắc, tôi nghĩ rằng tôi đã đạt được phạm vi khối bằng cách dán mã bên trong khai báo lớp:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
print(x)
Thật không may, điều này bị hỏng khi một hàm được xác định:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(x)
printx2()
Đó là bởi vì các hàm được định nghĩa trong một lớp sử dụng phạm vi toàn cầu. Cách dễ nhất (mặc dù không phải là duy nhất) để khắc phục điều này là chỉ định rõ ràng lớp:
x = 5
class BlockScopeAttempt:
x = 10
print(x)
def printx2():
print(BlockScopeAttempt.x)
printx2()
Điều này không quá thanh lịch vì người ta phải viết các hàm khác nhau tùy thuộc vào việc chúng có chứa trong một lớp hay không.
Kết quả tốt hơn với các mô-đun Python
Mô-đun rất giống với các lớp tĩnh, nhưng theo kinh nghiệm của tôi, các mô-đun sạch hơn nhiều. Để làm tương tự với các mô-đun, tôi tạo một tệp được gọi my_module.py
trong thư mục làm việc hiện tại với nội dung sau:
x = 10
print(x)
def printx():
global x
print(x)
Sau đó, trong tệp chính hoặc phiên tương tác (ví dụ: Jupyter), tôi
x = 5
import my_module
my_module.printx()
print(x)
Theo giải thích, mỗi tệp Python xác định một mô-đun có không gian tên chung của riêng nó. Nhập một mô-đun cho phép bạn truy cập các biến trong không gian tên này bằng .
cú pháp.
Nếu bạn đang làm việc với các mô-đun trong một phiên tương tác, bạn có thể thực hiện hai dòng này ở đầu
%load_ext autoreload
%autoreload 2
và các mô-đun sẽ được tự động tải lại khi các tệp tương ứng của chúng được sửa đổi.
Các gói để tải và lọc dữ liệu
Ý tưởng về các gói là một phần mở rộng nhẹ của khái niệm mô-đun. Gói là một thư mục chứa __init__.py
tệp (có thể trống) , tệp này được thực thi khi nhập. Các mô-đun / gói trong thư mục này có thể được truy cập bằng .
cú pháp.
Để phân tích dữ liệu, tôi thường cần đọc một tệp dữ liệu lớn và sau đó áp dụng các bộ lọc khác nhau một cách tương tác. Đọc một tập tin mất vài phút, vì vậy tôi chỉ muốn làm điều đó một lần. Dựa trên những gì tôi học được ở trường về lập trình hướng đối tượng, tôi từng tin rằng người ta nên viết mã để lọc và tải dưới dạng các phương thức trong một lớp. Một nhược điểm lớn của phương pháp này là nếu sau đó tôi xác định lại các bộ lọc của mình, định nghĩa về lớp của tôi sẽ thay đổi, vì vậy tôi phải tải lại toàn bộ lớp, bao gồm cả dữ liệu.
Ngày nay với Python, tôi định nghĩa một gói được gọi là gói my_data
chứa các mô-đun con có tên load
và filter
. Inside of filter.py
I có thể thực hiện nhập tương đối:
from .load import raw_data
Nếu tôi sửa đổi filter.py
, sau đó autoreload
sẽ phát hiện các thay đổi. Nó không tải lại load.py
, vì vậy tôi không cần tải lại dữ liệu của mình. Bằng cách này, tôi có thể tạo nguyên mẫu mã lọc của mình trong sổ ghi chép Jupyter, bọc nó dưới dạng một hàm, sau đó cắt dán trực tiếp từ sổ ghi chép của tôi vào filter.py
. Việc tìm ra điều này đã tạo ra một cuộc cách mạng trong quy trình làm việc của tôi và chuyển đổi tôi từ một người hoài nghi thành một người tin tưởng vào “Zen của Python”.
One purpose (of many) is to improve code readability
- Mã Python, được viết chính xác (tức là theo zen của python ) sẽ không cần trang trí như vậy để có thể đọc được. Trên thực tế, nó là một trong (nhiều) điều tôi thích về Python.