Bộ tiền xử lý của Python
(pydong.org)Bộ tiền xử lý của Python
- Khẳng định rằng Python không có bộ tiền xử lý là không đúng
- Python có một bộ tiền xử lý rất mạnh
Mã hóa mã nguồn Python
- Nhờ PEP-0263, có thể định nghĩa mã hóa cho mã nguồn
- Có thể thiết lập mã hóa bằng cách thêm magic comment vào hai dòng đầu tiên
- Ví dụ:
# coding=utf8,# -*- coding: utf8 -*-,# vim: set fileencoding=utf8 :
Tệp cấu hình đường dẫn (.pth)
- Khi trình thông dịch Python khởi động mà không có tùy chọn
-S, nó sẽ tự động nạp góisite - Có thể mở rộng đường dẫn tìm kiếm mô-đun bằng cách thêm tệp
.pthvào thư mụcsite-packages - Các dòng trong tệp
.pthbắt đầu bằngimportsẽ được thực thi - Nhờ đó có thể chạy mã tùy ý khi trình thông dịch Python khởi tạo
Định nghĩa codec tùy chỉnh
- Trình thông dịch Python cần thỏa mãn hai yêu cầu:
- hàm
decode(data: bytes) -> tuple[str, int] - một lớp bộ giải mã tăng dần
- hàm
- Dùng
codecs.utf_8_decodeđể thực hiện việc giải mã thực tế, rồi chuyển chuỗi kết quả cho bộ tiền xử lý - Nên bắt ngoại lệ, in ra rồi phát sinh lại
Cung cấp bộ giải mã tăng dần
- Kế thừa
codecs.BufferedIncrementalDecoderđể triển khai bộ giải mã tăng dần - Thu thập dữ liệu vào bộ đệm và tiền xử lý toàn bộ tệp ở lần gọi giải mã cuối cùng
Mở rộng Python
- Việc mở rộng Python bằng thư viện chuẩn của Python là tương đối dễ
- Có thể dùng mô-đun
tokenizeđể sửa luồng token của tệp hoặc dùng mô-đunastđể sửa cây cú pháp trừu tượng
Tăng và giảm đơn ngôi
- Python không có toán tử tăng và giảm đơn ngôi
x++,x--là không hợp lệ++x,--xlà hợp lệ nhưng mang ý nghĩa khác- Có thể chuyển các biểu thức tăng và giảm đơn ngôi sang biểu thức Python
Ví dụ
- Tệp đầu vào
incdec.py:# coding: magic.incdec i = 6 assert i-- == 6 assert i == 5 assert ++i == 6 assert --i == 5 assert i++ == 5 assert i == 6 assert (++i, 'i++') == (7, 'i++') print("PASSED") - Tệp sau khi chuyển đổi:
i = 6 assert ((i, i := i - 1)[0]) == 6 assert i == 5 assert ((i, i := i + 1)[1]) == 6 assert ((i, i := i - 1)[1]) == 5 assert ((i, i := i + 1)[0]) == 5 assert i == 6 assert (((i, i := i + 1)[1]), 'i++') == (7, 'i++') print("PASSED")
Python dùng dấu ngoặc nhọn (Bython)
- Có thể dùng dấu ngoặc nhọn để chỉ định phạm vi thay cho thụt lề của Python
- Dùng
tokenize.generate_tokensđể sửa luồng token
Ví dụ
- Tệp đầu vào
test.by:# coding: magic.braces def print_message(num_of_times) { for i in range(num_of_times) { print("braces ftw") } print({'x': 3}) } x = { 'foo': 42, 'bar': 5 } if __name__ == "__main__" { print_message(2) print({k: v for k, v in x.items()}) } - Tệp sau khi chuyển đổi:
def print_message(num_of_times): for i in range(num_of_times): print("braces ftw") print({'x': 3}) x = { 'foo': 42, 'bar': 5 } if __name__ == "__main__": print_message(2) print({k: v for k, v in x.items()})
Diễn giải ngôn ngữ khác
- Có thể khiến trình thông dịch Python diễn giải các ngôn ngữ khác
- Ví dụ: C, C++, TOML
Ví dụ
- Tệp C++
test.cpp:#define CODEC "coding:magic.cpp" #include <cstdio> int main() { puts("Hello World"); } - Tệp sau khi chuyển đổi:
import cppyy cppyy.cppdef(r""" #define CODEC "coding:magic.cpp" #include <cstdio> int main() { puts("Hello World"); } """) from cppyy.gbl import main if __name__ == "__main__": main()
Kiểm chứng dữ liệu
- Có thể kiểm chứng dữ liệu định dạng TOML bằng JSON Schema
- Dùng
jsonschemađể thực hiện việc kiểm chứng thực tế
Ví dụ
- Tệp schema
schema.json:{ "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "number"}, "scores": { "type": "array", "items": {"type": "number"} }, "address": {"$ref": "#/$defs/address"} }, "required": ["name"], "$defs": { "address": { "type": "object", "properties": { "street": {"type": "string"}, "postcode": {"type": "number"} }, "required": ["street"] } } } - Tệp dữ liệu hợp lệ
data_valid.toml:# coding: magic.toml name = "John Doe" age = 42 scores = [40, 20, 80, 90] [address] street = "Grove St. 4" postcode = 19201 - Tệp dữ liệu không hợp lệ
data_invalid.toml:# coding: magic.toml name = "John Doe" age = 42 scores = [40, "20", 80, 90] [address] street = "Grove St. 4" postcode = 19201
Kết luận
- Có thể thay đổi đáng kể hành vi của trình thông dịch Python bằng codec tùy chỉnh và tệp cấu hình đường dẫn
- Các ví dụ gồm
pythonql,future-typing,future-fstrings,future-annotations - Có thể dễ dàng thử nghiệm bộ tiền xử lý của riêng mình bằng
magic_codec
Tóm tắt của GN⁺
- Có thể tận dụng bộ tiền xử lý của Python để thực hiện nhiều kiểu mở rộng ngôn ngữ và kiểm chứng dữ liệu khác nhau
- Bài viết giải thích cách thay đổi hành vi của trình thông dịch Python thông qua codec tùy chỉnh
- Bài viết này cung cấp các công cụ và kỹ thuật hữu ích cho lập trình viên Python
- Các dự án có tính năng tương tự gồm
pythonql,future-typingv.v.
1 bình luận
Bình luận trên Hacker News
Thông báo lỗi cú pháp của
from __future__ import bracesđã được hard-code trong cpython từ năm 2001Tôi đã nghĩ về một cách sa thải đầy sáng tạo bằng import-hooks, nhưng tiếc là regex của codec chặn việc dùng thứ như
μtf8sys.settraceđể monkey-patch mọi hàm thành hàm đã được gọi trước đó, rồi hoán đổi stdout và stderr mỗi 17 phútCó lý do vì sao Python không phơi bày preprocessor hook, và tôi nghĩ người trưởng thành lý trí nên tránh nó
Preprocessor tiện và hữu ích hơn
exit()Tôi yêu sự linh hoạt của Python
Trường hợp dùng hay nhất với pyxl được lấy cảm hứng từ jsx
# coding: pyxlTự hỏi liệu quá trình chuyển từ Python 2 sang 3 có thể được xử lý tốt hơn không
# coding: six.python2có thể khiến mã Python2 hợp lệ trên Python3, còn# coding: six.python3có thể điều chỉnh mã Python3 để chạy được trên Python2Tôi rất vui vì mọi người thích ý tưởng này, sắp sẽ có thêm nội dung
Lâu rồi tôi mới thấy ngạc nhiên trước một ý tưởng hoàn toàn mới
Nếu muốn tạo mã inline trong Python, bạn có thể dùng cog của Ned Batchelder
Tôi tò mò liệu các dependency được đưa vào bằng chiến lược coding hook này có bị
pip freezehay uv phát hiện không