Python unicode so với chuỗi

và khi đi tìm giải pháp thì bị trục trặc đầu vào ma với các khái niệm giải mã, mã hóa và khi chúng ta sử dụng bất kỳ loại bảng mã Unicode, UTF-8, SHIFT-JIS nào. xì xì ngoằng. Mình sẽ giúp các bạn làm sáng tỏ một số vấn đề trên

2. Các khái niệm

a, Bảng mã Unicode, UTF-8, SHIFT-JIS. là gì?

  • Bảng mã Unicode là bảng mã chứa gần như toàn bộ các ký tự của hầu hết các ngôn ngữ trên toàn cầu. Có nghĩa là gần như bất kỳ ký tự nào mã hóa đều được thông qua bảng mã Unicode. Và mỗi ký tự sẽ tương ứng với một mã hóa byte. Trong python, các ký tự mã hóa Unicode được bắt đầu bằng chữ
    WARNING:root:��{�ꕶ�������e�X�g/
    
    3. Ví dụ chữ
    WARNING:root:��{�ꕶ�������e�X�g/
    
    4được mã hóa là
    WARNING:root:��{�ꕶ�������e�X�g/
    
    5
  • Bảng mã UTF-8 là bảng mã hóa miêu tả bảng mã Unicode cho máy tính hiểu
  • SHIFT-JIS là bảng mã được sử dụng gần như toàn bộ máy tính tại Nhật Bản, được JIS đưa ra. Nó cũng có tác dụng tương tự như bảng mã UTF-8 là miêu tả ký tự cho máy tính hiểu. Vì vậy Unicode là một Bộ ký tự [còn nhiều loại Bộ ký tự khác], một bộ tập hợp các ký tự cho con người sử dụng, còn UTF-8, SHIFT-JIS, ASCII. là những Character Encoding, chúng mã hóa các ký tự thành các con số để giúp máy tính hiểu được.

b, Chuỗi, giải mã, mã hóa trong python 2

  • Chuỗi trong python cũng là một đối tượng và được chia ra làm 2 loại [loại].
    WARNING:root:��{�ꕶ�������e�X�g/
    
    6 và
    WARNING:root:��{�ꕶ�������e�X�g/
    
    0. Một chuỗi là kiểu
    WARNING:root:��{�ꕶ�������e�X�g/
    
    0 thì sẽ có chữ
    WARNING:root:��{�ꕶ�������e�X�g/
    
    2 đứng trước khi in. VD.
    WARNING:root:��{�ꕶ�������e�X�g/
    
    3. Mặc định trong python 2 thì mọi chuỗi sẽ đều được đưa về kiểu
    WARNING:root:��{�ꕶ�������e�X�g/
    
    6
  • Giải mã và Mã hóa là cách chuyển đổi qua lại giữa
    WARNING:root:��{�ꕶ�������e�X�g/
    
    6 và
    WARNING:root:��{�ꕶ�������e�X�g/
    
    0

3. Các vấn đề xảy ra khi làm việc với Unicode

Thông thường khi mã hoặc tương tác với các dữ liệu có nội dung là tiếng anh, chỉ chứa các ký tự latinh thông thường thì gần như chẳng gặp vấn đề gì, chỉ khi tương tác với các ký tự đặc biệt, các ký tự có

1, Sử dụng Unicode trong code

Các bạn hãy thử viết đoạn mã sau vào tệp và chạy chúng

print "Xin chào Việt Nam"

các bạn sẽ gặp lỗi ngay sau đó

để sửa lỗi trên, ta sẽ thêm dòng
WARNING:root:��{�ꕶ�������e�X�g/
7 vào dòng đầu tiên của tệp để mã hóa toàn bộ chuỗi trong tệp đó bằng utf-8

2, Độ dài của chuỗi

Xem ví dụ sau

Tại sao khi thêm chữ

WARNING:root:��{�ꕶ�������e�X�g/
2 vào phía trước thì nó còn 10 ký tự. Because in python 2 default string will be to type
WARNING:root:��{�ꕶ�������e�X�g/
6 and used table code UTF-8 to code. Hãy xem thực tế chữ
print "Xin chào Việt Nam"
0 và
print "Xin chào Việt Nam"
1 được biểu diễn như thế nào

Tôi cho rằng đây có thể là thời điểm thích hợp để thực hiện phần giới thiệu cập nhật về unicode trong Python. Chủ yếu là vì chương unicode có rất nhiều chương mới khó hiểu về Python 3 mà nhà phát triển cần biết

Trước tiên hãy bắt đầu với cách unicode hoạt động trên Python 2

Unicode trên Python 2

Unicode trên Python 2 là một điều khá đơn giản. Có hai loại chuỗi ký tự. bytestrings [trông như thế này trên 2. x. 'foo'] và chuỗi unicode [có tiền tố u ở đầu như thế này. u'foo']. kể từ 2. 6, bạn cũng có thể nói rõ ràng về chuỗi phụ và viết chúng bằng tiền tố b ở đầu như thế này. b'foo'

Vấn đề lớn nhất của Python 2 với unicode là một số API không hỗ trợ nó. Những cái phổ biến nhất là nhiều hoạt động của hệ thống tệp, mô-đun datetime, trình đọc csv và khá nhiều phần bên trong trình thông dịch. Ngoài ra, một số API chỉ hoạt động với các chuỗi không phải unicode hoặc gây ra nhiều nhầm lẫn nếu bạn giới thiệu unicode. Chẳng hạn, các chuỗi tài liệu phá vỡ một số công cụ nếu chúng là unicode thay vì chuỗi byte, giá trị trả về của __repr__ chỉ được là byte chứ không phải chuỗi unicode, v.v.

Bên cạnh đó, Python có một tính năng thường khiến các nhà phát triển bối rối. một chuỗi byte miễn là nó chỉ chứa các ký tự ASCII có thể được nâng cấp hoàn toàn thành một chuỗi unicode. Tuy nhiên, nếu nó không an toàn với ASCII, nó sẽ gây ra một số dạng UnicodeError. UnicodeEncodeErrror hoặc UnicodeDecodeError tùy thuộc vào thời điểm không thành công

Vì tất cả những quy tắc ngón tay cái trên 2. x là cái này

  • lần đầu tiên bạn biết mã hóa của mình giải mã chính xác từ byte thành unicode
  • khi nó thuận tiện nhất cho bạn và bạn biết mã hóa mục tiêu, hãy mã hóa lại thành byte
  • trong nội bộ, vui lòng sử dụng byte bằng chữ miễn là chúng bị giới hạn trong tập hợp con ascii

Điều này làm việc thực sự tốt cho nhiều 2. thư viện x. Ví dụ, trên Flask, bạn sẽ chỉ gặp phải sự cố unicode nếu bạn cố gắng chuyển các chuỗi ký tự byte có ký tự không phải mã ascii vào mẫu hoặc nếu bạn cố gắng sử dụng Flask với các API không hỗ trợ unicode. Bên cạnh đó, phải mất rất nhiều công sức để tạo lỗi unicode

Điều này được thực hiện vì toàn bộ lớp WSGI dựa trên byte và toàn bộ lớp Flask dựa trên unicode [đối với văn bản]. Vì vậy, Flask chỉ thực hiện mã hóa khi nó chuyển từ WSGI sang Flask. Tương tự như vậy, giá trị trả về được kiểm tra và nếu kiểu trả về là unicode, nó sẽ tự động mã hóa nó trước khi xử lý dữ liệu trở lại lớp WSGI

Unicode cơ bản trên Python 3

Trên Python 3, có hai điều đã xảy ra khiến unicode trở nên phức tạp hơn rất nhiều. Vấn đề lớn nhất là chuỗi byte đã bị xóa. Nó đã được thay thế bằng một đối tượng gọi là byte được tạo bởi cú pháp 3 byte của Python. b'foo'. Nó có thể trông giống như một chuỗi lúc đầu, nhưng nó không phải. Thật không may, nó không chia sẻ nhiều API với các chuỗi

Ví dụ mã sau đây cho thấy đối tượng byte thực sự rất khác với đối tượng chuỗi

WARNING:root:��{�ꕶ�������e�X�g/
0

Người ta có thể lập luận rằng điều đó tốt, bởi vì bạn sẽ không còn trộn byte và unicode nữa, nhưng thật không may, đó không phải là trường hợp. Lý do cho điều này là toàn bộ API hoạt động trên byte và chuỗi unicode có thể hoán đổi cho nhau. Chẳng hạn, tất cả các API hệ thống tệp hoạt động trên cả unicode và byte

WARNING:root:��{�ꕶ�������e�X�g/
1

Điều đó thoạt nghe có vẻ không phải là vấn đề lớn, nhưng các API có thái độ lan rộng hơn nữa. Chẳng hạn, mở một tệp sẽ đặt thuộc tính tên thành một “chuỗi” của loại đó

WARNING:root:��{�ꕶ�������e�X�g/
2

Kết quả là mọi người dùng của. thuộc tính tên sẽ phải buộc nó đúng loại trước khi tương tác với nó. Điều tương tự cũng xảy ra trên 2. x, tuy nhiên trên 3. x hành vi này hầu hết là không có giấy tờ

Đó không chỉ là hoạt động của tệp, nó còn xảy ra trên các API khác như mô-đun phân tích cú pháp urllib có thể tạo ra cả byte và chuỗi unicode

WARNING:root:��{�ꕶ�������e�X�g/
3

Mặc định ma thuật trong 3. x

Thật không may, Python 3 đã lựa chọn đoán hơi quá nhiều với unicode ở một số nơi. Khi tôi đặt câu hỏi tại một hội nghị trước đây về việc mọi người tin rằng mã hóa mặc định cho các tệp văn bản trên Python 3 là gì, hầu hết đều trả lời UTF-8. Điều này đúng trên một số hệ điều hành. Điều đó hoàn toàn đúng với OS X và nó đúng với hầu hết các bản phân phối linux mà tôi đã thử. Tuy nhiên làm thế nào để Python xác định mã hóa đó?

Thật không may những phá vỡ rất nhanh chóng. Một ví dụ điển hình là SSH'ing từ ngôn ngữ tiếng Đức vào hộp linux của Hoa Kỳ không hỗ trợ ngôn ngữ tiếng Đức. Sau đó, Linux sẽ cố gắng đặt ngôn ngữ và không thành công và mặc định là C là ASCII. Python sau đó rất vui vẻ mở một tệp ở chế độ ASCII. Đây là logic mà Python áp dụng để đoán mã hóa mặc định trên các tệp

  1. đầu tiên, nó bắt đầu tìm thiết bị chứa tệp và sẽ cố lấy mã hóa từ thiết bị đó. Chức năng này hiện chỉ làm điều gì đó cho thiết bị đầu cuối. Theo như tôi biết thì điều này chỉ thực hiện một điều gì đó thực sự thú vị trên các cửa sổ nơi nó có thể trả về một trang mã [hoàn toàn không phải là unicode, nhưng điều đó được mong đợi]
  2. Chức năng tương tự tìm ra mã hóa thiết bị cũng có thể gọi nl_langinfo[CODESET] trả về mã hóa hiện tại mà hệ thống ngôn ngữ biết. Theo truyền thống, hỗ trợ ngôn ngữ không được khởi tạo trên trình thông dịch Python nhưng nó chắc chắn được khởi tạo ở đâu đó. Cuộc gọi này cũng là cuộc gọi có thể thất bại khi ngôn ngữ không khả dụng nhưng được đặt [ví dụ SSH ở trên]
  3. Nếu vì bất kỳ lý do gì device_encoding không trả về bất kỳ thứ gì [ví dụ: vì thiết bị không phải là thiết bị đầu cuối], nó sẽ cố gắng nhập mô-đun ngôn ngữ [BTW được viết bằng Python, luôn thú vị khi xem nội dung được viết bằng C nhập mô-đun Python . getpreferredencoding và sử dụng giá trị trả về của hàm đó

Bởi vì nó không đặt ngôn ngữ ở đó nên về cơ bản nó chỉ gọi lại nl_langinfo[CODESET]. Bởi vì cuộc gọi đó đôi khi không thành công trên OS X, nó chuyển đổi giá trị trả về cho OS X thành utf-8 nếu không nhận được kết quả hữu ích

Tôi không phải là người thích hành vi đó và tôi thực sự khuyên bạn nên chuyển rõ ràng mã hóa tệp văn bản làm tham số thứ ba. Đó là cách chúng tôi đã làm trên 2. x và đó cũng là cách tôi khuyên bạn nên thực hiện trên Python 3. Tôi thực sự muốn mã hóa mặc định được thay đổi thành utf-8 trong mọi trường hợp ngoại trừ thiết bị đầu cuối và có thể có một số mã hóa = 'tự động' cờ đoán

Tôi đã không cài đặt được gói trên python 3 trước đây vì tên người đóng góp chứa tên không phải ASCII và thiết lập. tệp py đang mở tệp README cho chuỗi tài liệu. Hoạt động tốt trên OS X và Linux thông thường, nhưng bị hỏng khi tôi SSH vào hộp Linux của mình từ OS X của Áo. Tôi không chắc có bao nhiêu người gặp phải vấn đề đó [tôi cho là không nhiều] nhưng thật khó chịu khi nó xảy ra và thực sự không có gì đảm bảo rằng tệp được mở ở chế độ văn bản và không có mã hóa xác định là UTF-8. Vì vậy, hãy ủng hộ thế giới và mở các tệp văn bản như thế này

WARNING:root:��{�ꕶ�������e�X�g/
4

Các loại chuỗi Unicode khác nhau

Ngoài các chuỗi unicode thông thường, trên Python 3, bạn phải xử lý thêm hai loại chuỗi unicode. Lý do là thư viện [hoặc trình thông dịch Python] không có đủ kiến ​​thức về mã hóa nên phải áp dụng một số thủ thuật. Ở đâu trong Python 2. x, chúng tôi đã tạo một chuỗi thành byte trong trường hợp đó, trên Python 3, bạn có thêm hai lựa chọn. Các chuỗi này không có tên riêng và trông giống như các chuỗi unicode thông thường, vì vậy tôi sẽ đặt tên cho chúng để tiện tranh luận. Hãy gọi chuỗi unicode thông thường là chuỗi “văn bản”. Mỗi ký tự trong chuỗi đó được thể hiện chính xác bên trong và không có bất ngờ nào được mong đợi

Ngoài ra, còn có các chuỗi mà tôi gọi là chuỗi "được giải mã vận chuyển". Những chuỗi đó được sử dụng ở một vài nơi. Trường hợp phổ biến nhất mà bạn đang xử lý các chuỗi đó là giao thức WSGI và hầu hết mọi thứ có giao diện với HTTP. WSGI tuyên bố rằng các chuỗi trong môi trường WSGI được biểu diễn dưới dạng các chuỗi latin1 được giải mã không chính xác. Nói cách khác, điều xảy ra là tất cả các chuỗi unicode trong môi trường Python 3 WSGI thực sự được mã hóa không chính xác cho bất kỳ điểm mã nào trên ASCII. Để giải mã chính xác chuỗi đó, bạn sẽ cần mã hóa chuỗi trở lại latin 1 và giải mã từ mã hóa dự định. Werkzeug gọi nội bộ các chuỗi như vậy là chuỗi "mã hóa điệu nhảy". Logic sau phải được áp dụng để giải mã lại chúng thành bộ ký tự thực tế

WARNING:root:��{�ꕶ�������e�X�g/
5

Logic này không chỉ được yêu cầu đối với WSGI, tuy nhiên, yêu cầu tương tự cũng xuất hiện đối với bất kỳ tiêu đề MIME và HTTP nào. Về mặt lý thuyết, đó không phải là vấn đề đối với các tiêu đề này vì chúng bị giới hạn ở latin1 ngoài hộp và sử dụng thông tin mã hóa rõ ràng nếu một chuỗi không vừa với latin1. Thật không may, trong điều kiện thực tế, không có gì lạ khi một số tiêu đề nhất định được mã hóa utf-8. Điều này cực kỳ phổ biến với các tiêu đề tùy chỉnh do ứng dụng phát ra cũng như tiêu đề cookie nếu tiêu đề cookie được đặt qua JavaScript vì API trình duyệt không cung cấp mã hóa tự động

Loại chuỗi thứ hai phổ biến trên Python 3 là "chuỗi thoát thay thế". Đây là các chuỗi unicode không thể được mã hóa thành bảng mã unicode vì chúng thực sự không hợp lệ. Các chuỗi này được tạo bởi các API nghĩ rằng một mã hóa là một mã cụ thể nhưng không thể đảm bảo nó vì hệ thống cơ bản không thực thi đầy đủ điều đó. Chức năng này được cung cấp bởi trình xử lý lỗi 'surrogateescape'

WARNING:root:��{�ꕶ�������e�X�g/
6

Điều này chẳng hạn xảy ra với hệ điều hành. environ cũng như tất cả các hàm hệ thống tập tin dựa trên unicode. Nếu bạn cố mã hóa một chuỗi như vậy thành utf-8 chẳng hạn, bạn sẽ nhận được lỗi UnicodeEncodeError.

WARNING:root:��{�ꕶ�������e�X�g/
7

Để giải quyết vấn đề này, bạn cần mã hóa các chuỗi đó bằng cách xử lý lỗi mã hóa được đặt thành 'surrogateescape'. Là một tiện ích mở rộng, điều này có nghĩa là các chuỗi nhận được từ các chức năng có thể mang đại diện thay thế cần được giải quyết trước khi chuyển tới các API không xử lý các chuỗi đó

Điều này chủ yếu có nghĩa là bạn có hai lựa chọn. thay đổi tất cả việc xử lý lỗi mã hóa [] của bạn ở bất kỳ đâu trong cơ sở mã của bạn từ 'strict' [là mặc định] thành 'surrogateescape' hoặc xóa các đại diện thay thế khỏi chuỗi của bạn. Hình thức đơn giản nhất mà tôi tin là trải qua một điệu nhảy mã hóa/giải mã. Tôi tin rằng hiện tại đó cũng là cách đơn giản duy nhất để kiểm tra xem có thứ gì đó thực sự thay thế đã trốn thoát hay không

Đề xuất của tôi là mỗi khi bạn xử lý một API có thể tạo ra các chuỗi thoát thay thế [os. môi trường vv. ] bạn chỉ nên thực hiện kiểm tra cơ bản nếu giá trị thay thế thoát và gây ra lỗi [hoặc loại bỏ thoát thay thế và gọi nó là một ngày]. Nhưng đừng chuyển tiếp các chuỗi đó trở đi vì sau này sẽ rất khó để tìm ra điều gì sai

Chẳng hạn, nếu bạn chuyển một chuỗi như vậy tới một công cụ mẫu, bạn sẽ hoàn toàn gặp lỗi ở một nơi khác và vì quá trình mã hóa xảy ra ở giai đoạn muộn hơn nhiều, bạn không còn biết tại sao chuỗi đó không chính xác. Nếu bạn phát hiện lỗi đó khi nó xảy ra, sự cố sẽ trở nên dễ gỡ lỗi hơn nhiều [về cơ bản khôi phục 2. hành vi x]

Các chức năng này có thể hữu ích

WARNING:root:��{�ꕶ�������e�X�g/
8

Cả hai chuỗi "transport decoded" và "surrogate escape" đều cùng loại với các chuỗi thông thường, vì vậy cách tốt nhất để phân biệt chúng là ghi nhớ nguồn gốc của chúng. Trong Werkzeug, tôi đã viết các hàm trợ giúp tìm nạp các chuỗi từ vùng chứa của chúng [môi trường WSGI] và giải mã chúng ngay lập tức để người dùng không bao giờ phải xử lý các chi tiết cấp thấp

Các giao diện sau đây tạo ra một số chuỗi đó

APIString Typeos. những người thoát khỏi môi trường. danh sách thư mục thay thế đã giải mã truyền tải môi trường WSGI đã giải mã [latin1]tiêu đề HTTP/MIME truyền tải đã giải mã [latin1]tải trọng văn bản email thay thế đã thoát khỏi ntplib tất cả dữ liệu thay thế thoát. exec* chức năng thay thế thoát [ngoại trừ trên windows] môi trường thay thế quy trình con thoát [ngoại trừ trên windows] đối số quy trình con thay thế thoát [ngoại trừ trên windows]

Ngoài ra còn có một số trường hợp đặc biệt trong stdlib nơi các chuỗi rất khó hiểu. cgi. Mô-đun FieldStorage mà các ứng dụng WSGI đôi khi vẫn đang sử dụng để phân tích cú pháp dữ liệu biểu mẫu hiện đang coi QUERY_STRING là thoát thay thế, nhưng thay vì sử dụng utf-8 làm bộ ký tự cho URL [dưới dạng trình duyệt], mô-đun này coi đó là mã hóa được trả về bởi ngôn ngữ. getpreferredencoding[]. Tôi không biết tại sao nó lại làm như vậy, nhưng nó không chính xác. Như một giải pháp thay thế, tôi khuyên bạn không nên sử dụng cgi. FieldStorage để phân tích cú pháp chuỗi truy vấn

Thật không may, các tài liệu thường rất im lặng về việc họ có đang sử dụng người thay thế thoát hay không. Nói chung cách tốt nhất là nhìn vào nguồn hiện tại

Phát hiện lỗi

Trên Python 2. x phát hiện lạm dụng Unicode khá đơn giản. Nói chung, nếu bạn đã làm những điều tinh ranh, bạn sẽ nhận được một số dạng UnicodeError hoặc UnicodeWarning. Thông thường, bạn có một UnicodeEncodeError hoặc UnicodeDecodeError nghiêm trọng hoặc bạn đã ghi một UnicodeWarning. Ví dụ, trường hợp thứ hai xảy ra khi so sánh byte và unicode trong đó các byte không thể được giải mã từ ASCII. Thật không may, trên Python 3, tình hình có vẻ rất khác

  • Lỗi thuộc tính. điều này thường xảy ra nếu bạn cố gắng sử dụng API chỉ chuỗi trên đối tượng byte. Thông thường, điều này xảy ra đối với các cuộc gọi đến casefold[], mã hóa[] hoặc định dạng[]
  • LoạiLỗi. điều này có thể xảy ra vì nhiều lý do khác nhau. Cái phổ biến nhất là định dạng chuỗi không hoạt động trên byte. Nếu bạn cố gắng thực hiện foo % bar và foo hóa ra là một đối tượng byte, bạn sẽ nhận được TypeError. Một hình thức khác của điều này là một cái gì đó lặp lại trên một chuỗi và mong đợi một chuỗi một ký tự được trả về nhưng thực tế lại tạo ra một số nguyên
  • UnicodeEncodeError. hiện thường xảy ra do sự cố thoát thay thế khi bạn không sử dụng trình xử lý lỗi 'surrogateescape' trên chuỗi mã hóa hoặc quên xóa thay thế khỏi chuỗi
  • unicode bị cắt xén. xảy ra nếu bạn không xử lý đúng các chuỗi được giải mã vận chuyển. Điều này thường xảy ra với WSGI. Cách tốt nhất để nắm bắt điều này là không bao giờ để lộ trực tiếp các chuỗi WSGI và luôn trải qua một mức độ gián tiếp bổ sung. Bằng cách đó, bạn không vô tình trộn lẫn các chuỗi unicode thuộc các loại khác nhau
  • không có lỗi. điều đó xảy ra chẳng hạn khi bạn so sánh byte và chuỗi và phép so sánh sẽ trả về Sai mà không đưa ra cảnh báo. Điều này có thể được khắc phục bằng cách chạy trình thông dịch Python với cờ -b sẽ phát ra cảnh báo về byte và so sánh văn bản.
  • hết bộ nhớ/chuỗi lớn. điều này xảy ra khi bạn cố chuyển một số nguyên lớn tới hàm tạo bytes[]. Tôi đã thấy điều này xảy ra một vài lần khi chuyển sang Python 3 trong đó mẫu là một dạng "nếu đối tượng không phải là một thể hiện của byte, hãy gọi byte[] trên đó". Điều này rất nguy hiểm vì số nguyên là giá trị đầu vào hợp lệ cho hàm tạo bytes[] sẽ phân bổ số byte null bằng số nguyên được truyền. Khuyến nghị là ngừng sử dụng mẫu đó và viết hàm soft_bytes để bắt các tham số số nguyên trước khi chuyển nó sang byte

Viết API kết hợp Unicode/Byte

Vì có rất nhiều trường hợp API có thể trả về cả byte hoặc chuỗi unicode tùy thuộc vào nguồn gốc của chúng, nên cần phải tạo các mẫu mới. Trong Python 2, vấn đề đó đã tự giải quyết vì chuỗi phụ được tự động thăng cấp thành chuỗi unicode. Trên Python 3, điều đó không còn xảy ra nữa, điều này khiến việc triển khai khó khăn hơn nhiều với các API thực hiện cả hai

Werkzeug và Flask sử dụng các trình trợ giúp sau để cung cấp [hoặc làm việc với] các API xử lý cả chuỗi và byte

WARNING:root:��{�ꕶ�������e�X�g/
9

Các chức năng này cùng nhau đi khá xa để làm cho API hoạt động cho cả chuỗi và byte. Chẳng hạn, đây là cách hoạt động của liên kết URL trong Werkzeug, được kích hoạt bởi trình trợ giúp normalize_string_tuple và make_literal_wrapper

WARNING:root:��{�ꕶ�������e�X�g/
10

Bằng cách này, hàm chỉ cần được viết một lần để xử lý cả byte và chuỗi, theo tôi, đây là một giải pháp hay hơn so với những gì thư viện chuẩn thực hiện, đó là thực hiện mọi chức năng hai lần, điều đó có nghĩa là rất nhiều thao tác sao chép/dán

Một vấn đề khác là gói các đối tượng tệp trong Python 3 vì hiện tại chúng chỉ hỗ trợ văn bản hoặc byte nhưng không có giao diện được ghi lại để tìm ra những gì chúng chấp nhận. Flask sử dụng cách giải quyết sau

WARNING:root:��{�ꕶ�������e�X�g/
11

Chẳng hạn, Flask sử dụng điều này để làm cho JSON hoạt động lại với cả văn bản và byte tương tự như cách nó hoạt động trong 2. x

WARNING:root:��{�ꕶ�������e�X�g/
12

Unicode khó

Unicode vẫn còn khó và theo kinh nghiệm của tôi, nó không dễ dàng hơn nhiều trên 3. x so với ngày 2. x. Trong khi quá trình chuyển đổi buộc tôi phải làm cho một số API hoạt động tốt hơn với unicode [và bây giờ chính xác hơn], tôi vẫn phải thêm rất nhiều mã bổ sung không cần thiết trên Python 2. Nếu ai đó làm một ngôn ngữ động khác trong tương lai, tôi tin rằng giải pháp chính xác sẽ là thế này

  1. thực hiện cách tiếp cận của Python 2. x và cho phép trộn byte và chuỗi unicode
  2. Đặt 'foo' nghĩa là chuỗi unicode và b'foo' nghĩa là chuỗi byte
  3. Tạo chuỗi byte có thuộc tính mã hóa mặc định là ASCII
  4. Thêm một phương thức để thay thế thông tin mã hóa [ví dụ:. b'foo'. replace_encoding_hint['latin1']
  5. Khi so sánh các chuỗi và byte, hãy sử dụng gợi ý mã hóa thay vì mặc định ASCII [hoặc mã hóa mặc định hệ thống chính xác hơn, tốt hơn hoặc tệ hơn luôn là ASCII]
  6. Có một loại byte riêng biệt hoạt động chính xác như các chuỗi không thể băm và không thể mang thông tin mã hóa và thường chỉ kêu khi cố gắng chuyển đổi nó thành chuỗi. Bằng cách đó, bạn có thể gắn thẻ dữ liệu nhị phân thực, đôi khi có thể hữu ích [ví dụ: đối với giao diện tuần tự hóa]

Nếu ai đó muốn xem mức độ phức tạp của hỗ trợ unicode mới trong Python 3, hãy xem mã của mô-đun os trên 3. x, các tiện ích vận hành tệp mô-đun io nội bộ và những thứ như urllib. phân tích cú pháp

Về mặt tươi sáng. không có gì thay đổi nhiều đối với người dùng Python cấp cao. Tôi nghĩ rằng Flask chẳng hạn cung cấp một trải nghiệm đơn giản cho unicode trên cả 2. x và 3. x. Người dùng gần như được bảo vệ hoàn toàn khỏi sự phức tạp của việc xử lý unicode. Cấp độ API càng cao thì mã hóa càng ít đóng vai trò trong đó

Chủ Đề