tokenize --- Tokenizer cho nguồn Python¶
Source code: Lib/tokenize.py
Mô-đun tokenize cung cấp trình quét từ vựng cho mã nguồn Python, được triển khai bằng Python. Máy quét trong mô-đun này cũng trả về các nhận xét dưới dạng mã thông báo, giúp nó hữu ích cho việc triển khai "máy in đẹp", bao gồm cả bộ tạo màu cho hiển thị trên màn hình.
Để đơn giản hóa việc xử lý luồng mã thông báo, tất cả mã thông báo operator, delimiter và Ellipsis đều được trả về bằng loại mã thông báo OP chung. Loại chính xác có thể được xác định bằng cách kiểm tra thuộc tính exact_type trên named tuple được trả về từ tokenize.tokenize().
Cảnh báo
Lưu ý rằng các hàm trong mô-đun này chỉ được thiết kế để phân tích mã Python hợp lệ về mặt cú pháp (mã không tăng khi được phân tích cú pháp bằng ast.parse()). Hoạt động của các hàm trong mô-đun này là undefined khi cung cấp mã Python không hợp lệ và nó có thể thay đổi bất kỳ lúc nào.
Đầu vào mã thông báo¶
Điểm vào chính là generator:
- tokenize.tokenize(readline)¶
Trình tạo
tokenize()yêu cầu một đối số, readline, phải là một đối tượng có thể gọi được và cung cấp giao diện giống như phương thứcio.IOBase.readline()của các đối tượng tệp. Mỗi lệnh gọi hàm sẽ trả về một dòng đầu vào dưới dạng byte.Trình tạo tạo ra 5 bộ dữ liệu với các thành viên này: loại mã thông báo; chuỗi mã thông báo; một
(srow, scol)2 bộ dữ liệu int chỉ định hàng và cột nơi mã thông báo bắt đầu trong nguồn; một(erow, ecol)2 bộ dữ liệu int chỉ định hàng và cột nơi mã thông báo kết thúc trong nguồn; và dòng mà mã thông báo được tìm thấy. Dòng được truyền (mục bộ cuối cùng) là dòng physical. Bộ thứ 5 được trả về dưới dạng named tuple với tên trường:type string start end line.named tuple được trả về có một thuộc tính bổ sung có tên
exact_typechứa loại toán tử chính xác cho mã thông báoOP. Đối với tất cả các loại mã thông báo khác,exact_typebằng với trườngtypetuple được đặt tên.Thay đổi trong phiên bản 3.1: Đã thêm hỗ trợ cho các bộ dữ liệu được đặt tên.
Thay đổi trong phiên bản 3.3: Đã thêm hỗ trợ cho
exact_type.tokenize()xác định mã hóa nguồn của tệp bằng cách tìm kiếm UTF-8 BOM hoặc cookie mã hóa, theo PEP 263.
- tokenize.generate_tokens(readline)¶
Mã hóa nguồn đọc chuỗi unicode thay vì byte.
Giống như
tokenize(), đối số readline là một đối số có thể gọi được và trả về một dòng đầu vào. Tuy nhiên,generate_tokens()mong đợi readline trả về một đối tượng str thay vì byte.Kết quả là một trình vòng lặp mang lại các bộ dữ liệu có tên, giống hệt như
tokenize(). Nó không mang lại mã thông báoENCODING.
Tất cả các hằng số từ mô-đun token cũng được xuất từ tokenize.
Một chức năng khác được cung cấp để đảo ngược quá trình mã hóa. Điều này hữu ích khi tạo các công cụ mã hóa tập lệnh, sửa đổi luồng mã thông báo và ghi lại tập lệnh đã sửa đổi.
- tokenize.untokenize(iterable)¶
Chuyển đổi mã thông báo trở lại mã nguồn Python. Zz000zz phải trả về các chuỗi có ít nhất hai phần tử, loại mã thông báo và chuỗi mã thông báo. Mọi phần tử trình tự bổ sung đều bị bỏ qua.
Kết quả được đảm bảo mã hóa trở lại để khớp với đầu vào để việc chuyển đổi không bị mất và các chuyến đi khứ hồi được đảm bảo. Bảo đảm chỉ áp dụng cho loại mã thông báo và chuỗi mã thông báo vì khoảng cách giữa các mã thông báo (vị trí cột) có thể thay đổi.
Nó trả về byte, được mã hóa bằng mã thông báo
ENCODING, đây là đầu ra chuỗi mã thông báo đầu tiên củatokenize(). Nếu không có mã thông báo mã hóa trong đầu vào thì thay vào đó, nó sẽ trả về một str.
tokenize() cần phát hiện mã hóa của tệp nguồn mà nó mã hóa. Chức năng nó sử dụng để thực hiện việc này có sẵn:
- tokenize.detect_encoding(readline)¶
Hàm
detect_encoding()được sử dụng để phát hiện mã hóa nên được sử dụng để giải mã tệp nguồn Python. Nó yêu cầu một đối số, readline, giống như cách tạotokenize().Nó sẽ gọi đường đọc tối đa hai lần và trả về mã hóa được sử dụng (dưới dạng chuỗi) và danh sách bất kỳ dòng nào (không được giải mã từ byte) mà nó đã đọc.
Nó phát hiện mã hóa từ sự hiện diện của UTF-8 BOM hoặc cookie mã hóa như được chỉ định trong PEP 263. Nếu có cả BOM và cookie nhưng không đồng ý thì
SyntaxErrorsẽ được nâng lên. Lưu ý rằng nếu tìm thấy BOM,'utf-8-sig'sẽ được trả về dưới dạng mã hóa.Nếu không chỉ định mã hóa thì giá trị mặc định là
'utf-8'sẽ được trả về.Sử dụng
open()để mở tệp nguồn Python: nó sử dụngdetect_encoding()để phát hiện mã hóa tệp.
- tokenize.open(filename)¶
Mở tệp ở chế độ chỉ đọc bằng cách sử dụng mã hóa được phát hiện bởi
detect_encoding().Added in version 3.2.
- exception tokenize.TokenError¶
Xảy ra khi một chuỗi tài liệu hoặc biểu thức có thể được chia thành nhiều dòng không được hoàn thành ở bất kỳ đâu trong tệp, ví dụ:
"""Bắt đầu chuỗi tài liệu
hoặc:
[1, 2, 3
Sử dụng dòng lệnh¶
Added in version 3.3.
Mô-đun tokenize có thể được thực thi dưới dạng tập lệnh từ dòng lệnh. Nó đơn giản như:
python -m tokenize [-e] [filename.py]
Các tùy chọn sau được chấp nhận:
- -h, --help¶
hiển thị thông báo trợ giúp này và thoát
- -e, --exact¶
hiển thị tên mã thông báo bằng loại chính xác
Nếu filename.py được chỉ định, nội dung của nó sẽ được mã hóa thành thiết bị xuất chuẩn. Mặt khác, quá trình mã hóa được thực hiện trên stdin.
Ví dụ¶
Ví dụ về trình viết lại tập lệnh chuyển đổi các ký tự float thành các đối tượng thập phân:
từ tokenize nhập tokenize, unkenize, NUMBER, STRING, NAME, OP
từ io nhập ByteIO
def deistmt(s):
"""Thay thế số thập phân cho số float trong chuỗi câu lệnh.
>>> từ nhập thập phân Thập phân
>>> s = 'print(+21.3e-5*-.1234/81.7)'
>>> quyết định
"in (+Thập phân ('21.3e-5')*-Thập phân ('.1234')/Thập phân ('81.7'))"
Định dạng của số mũ được kế thừa từ thư viện nền tảng C.
Các trường hợp đã biết là "e-007" (Windows) và "e-07" (không phải Windows). Kể từ khi
chúng tôi chỉ hiển thị 12 chữ số và số 13 không gần bằng 5,
phần còn lại của đầu ra phải độc lập với nền tảng.
>>> (các) người thực thi #doctest: +ELLIPSIS
-3.21716034272e-0...7
Đầu ra từ các phép tính với Decimal phải giống hệt nhau trên tất cả
nền tảng.
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
"""
kết quả = []
g = tokenize(BytesIO(s.encode('utf-8')).readline) # tokenize chuỗi
cho toknum, tokval, _, _, _ trong g:
nếu toknum == NUMBER và '.' trong tokval: mã thông báo # replace NUMBER
result.extend([
(NAME, 'Thập phân'),
(OP, '('),
(STRING, đại diện (tokval)),
(OP, ')')
])
khác:
result.append((toknum, tokval))
trả về unkenize(result).decode('utf-8')
Ví dụ về mã thông báo từ dòng lệnh. Kịch bản:
chắc chắn say_hello():
print("Xin chào thế giới!")
say_hello()
sẽ được mã hóa thành đầu ra sau trong đó cột đầu tiên là phạm vi tọa độ dòng/cột nơi tìm thấy mã thông báo, cột thứ hai là tên của mã thông báo và cột cuối cùng là giá trị của mã thông báo (nếu có)
$ python -m token hóa hello.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,3: NAME 'def'
1,4-1,13: NAME 'say_hello'
1,13-1,14: OP '('
1,14-1,15: OP ')'
1,15-1,16: OP':'
1,16-1,17: NEWLINE '\n'
2,0-2,4: INDENT ''
2,4-2,9: NAME 'in'
2,9-2,10: OP '('
2,10-2,25: STRING '"Xin chào thế giới!"'
2,25-2,26: OP ')'
2,26-2,27: NEWLINE '\n'
3,0-3,1: NL '\n'
4,0-4,0: DEDENT''
4,0-4,9: NAME 'say_hello'
4,9-4,10: OP '('
4,10-4,11: OP ')'
4,11-4,12: NEWLINE '\n'
5,0-5,0: ENDMARKER''
Tên loại mã thông báo chính xác có thể được hiển thị bằng tùy chọn -e:
$ python -m tokenize -e hello.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,3: NAME 'def'
1,4-1,13: NAME 'say_hello'
1,13-1,14: LPAR '('
1,14-1,15: RPAR ')'
1,15-1,16: COLON ':'
1,16-1,17: NEWLINE '\n'
2,0-2,4: INDENT ''
2,4-2,9: NAME 'in'
2,9-2,10: LPAR '('
2,10-2,25: STRING '"Xin chào thế giới!"'
2,25-2,26: RPAR ')'
2,26-2,27: NEWLINE '\n'
3,0-3,1: NL '\n'
4,0-4,0: DEDENT''
4,0-4,9: NAME 'say_hello'
4,9-4,10: LPAR '('
4,10-4,11: RPAR ')'
4,11-4,12: NEWLINE '\n'
5,0-5,0: ENDMARKER ''
Ví dụ về mã hóa tệp theo chương trình, đọc chuỗi unicode thay vì byte bằng generate_tokens():
nhập mã thông báo
với tokenize.open('hello.py') là f:
mã thông báo = tokenize.generate_tokens(f.readline)
đối với mã thông báo trong mã thông báo:
in (mã thông báo)
Hoặc đọc byte trực tiếp với tokenize():
nhập mã thông báo
với open('hello.py', 'rb') là f:
mã thông báo = tokenize.tokenize(f.readline)
đối với mã thông báo trong mã thông báo:
in (mã thông báo)