Giải nén một đối tượng python 2 với python 3


129

Tôi tự hỏi liệu có cách nào để tải một đối tượng được ngâm trong Python 2.4, với Python 3.4.

Tôi đã chạy 2to3 trên một số lượng lớn mã kế thừa của công ty để cập nhật mã này.

Làm xong việc này, khi chạy tập tin tôi gặp lỗi sau:

  File "H:\fixers - 3.4\addressfixer - 3.4\trunk\lib\address\address_generic.py"
, line 382, in read_ref_files
    d = pickle.load(open(mshelffile, 'rb'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 1: ordinal
not in range(128)

Nhìn vào đối tượng ngâm trong tranh chấp, đó là dictmột dict, chứa các khóa và giá trị của loại str.

Vì vậy, câu hỏi của tôi là: Có cách nào để tải một đối tượng, ban đầu được ngâm trong python 2.4, với python 3.4 không?


1
Python 2.4 có jsonmô-đun không? Có lẽ bạn có thể viết một tập lệnh 2.4 để giải nén đối tượng và lưu nó dưới dạng đối tượng json, sau đó viết tập lệnh 3,4 đọc đối tượng json và lưu nó dưới dạng đối tượng pickle tương thích 3,4. Đây sẽ là hoạt động một lần mà bạn chạy trên tất cả các tệp dưa chua của mình.
Kevin

Tôi đã suy nghĩ theo các dòng tương tự, xem xét rằng đây là những điều tôi nghĩ rằng tôi chỉ có thể thay đổi sys.stdout thành một tệp và in chúng ra, nhưng tôi muốn xem liệu tôi có thể tải chúng trước không
NDevox

Câu hỏi liên quan phải làm với datetimes cụ thể: stackoverflow.com/questions/24805105/ trên
John Y

Câu trả lời:


189

Bạn sẽ phải cho biết pickle.load()cách chuyển đổi dữ liệu bằng cách kiểm tra dữ liệu của Python thành các chuỗi Python 3 hoặc bạn có thể yêu cầu pickleđể lại chúng dưới dạng byte.

Mặc định là thử và giải mã tất cả dữ liệu chuỗi dưới dạng ASCII và việc giải mã đó thất bại. Xem pickle.load()tài liệu :

Đối số từ khóa tùy chọn là fix_imports , mã hóalỗi , được sử dụng để kiểm soát hỗ trợ tương thích cho luồng dưa chua được tạo bởi Python 2. Nếu fix_imports là đúng, Pickle sẽ cố gắng ánh xạ tên Python 2 cũ sang tên mới được sử dụng trong Python 3. mã hóalỗi cho Pickle biết cách giải mã các trường hợp chuỗi 8 bit được chọn bởi Python 2; những cái này mặc định là 'ASCII' và 'nghiêm ngặt', tương ứng. Các mã hóa có thể là 'byte' để đọc những trường hợp này 8-bit chuỗi như byte đối tượng.

Đặt mã hóa để latin1cho phép bạn nhập dữ liệu trực tiếp:

with open(mshelffile, 'rb') as f:
    d = pickle.load(f, encoding='latin1') 

nhưng bạn sẽ cần xác minh rằng không có chuỗi nào của bạn được giải mã bằng cách sử dụng codec sai; Latin-1 hoạt động cho mọi đầu vào vì nó ánh xạ các giá trị byte 0-255 đến 256 điểm mã Unicode đầu tiên trực tiếp.

Cách khác là tải dữ liệu encoding='bytes'và giải mã tất cả bytescác khóa và giá trị sau đó.

Lưu ý rằng tối đa các phiên bản Python trước 3.6.8, 3.7.2 và 3.8.0, việc giải nén datetimedữ liệu đối tượng Python 2 bị hỏng trừ khi bạn sử dụng encoding='bytes'.


1
Làm thế nào điều này có thể được thực hiện tương thích ngược với Python 2? Rõ ràng, đối số mã hóa không xuất hiện cho Python 2.
EpicAdv

2
@EpicAdv: bạn không cần phải làm cho mã này tương thích với Python 2; câu hỏi này là về cách tải dưa chua Python 2 vào Python 3. Bỏ encodinghoàn toàn từ khóa cho Python 2.
Martijn Pieters

10
@EpicAdv: Bạn có thể tạo một từ điển pickle_options trống cho python 2 hoặc có 'encoding': 'latin1'và gửi ** pickle_options cho dưa chua. Bằng cách này, nó sẽ chạy trong cả hai phiên bản.
Pipefish

@pipefish - Thông minh, nhưng ở đâu đó bạn phải phát hiện phiên bản nào bạn đang sử dụng, do đó, bạn cũng có thể thực hiện cuộc gọi một cách khác biệt (một với một và không có đối số phụ) tùy thuộc vào phiên bản. Nhưng ít nhất bạn đã nhận được ý chính của bình luận của EpicAdv, mà bình luận của Martijn hoàn toàn không đề cập đến.
John Y

2
Tôi nhận ra nhận datetimexét không phải là lực đẩy chính của câu trả lời này, nhưng đối với những độc giả tương lai, tôi muốn chỉ ra rằng ngay cả các phiên bản "cố định" của Python 3 vẫn yêu cầu encoding='latin-1'giải nén dữ liệu của Python 2. Nếu dữ liệu Python 2 được chọn của bạn tình cờ bao gồm cả datetimes và bytestrings được mã hóa trong một cái gì đó không phải là Latin-1, thì encoding='bytes'sau tất cả , bạn vẫn có thể sử dụng tốt hơn .
John Y

15

Việc sử dụng encoding='latin1'gây ra một số vấn đề khi đối tượng của bạn chứa các mảng numpy trong đó.

Sử dụng encoding='bytes'sẽ tốt hơn.

Xin vui lòng xem câu trả lời này để được giải thích đầy đủ về việc sử dụngencoding='bytes'


Vấn đề nào? Tôi nên cẩn thận những gì? bằng cách sử dụng byteslàm cho chuỗi thành byte (), vì vậy tôi thích latin1nếu có thể, nhưng tôi không rõ vấn đề là gì.
Gulzar

2
@ sreeragh-ar: Bạn có thể đưa ra một ví dụ về các vấn đề bạn gặp phải không? Tôi có một công cụ numpy.ndarrayngâm hai chiều (numpy 1.14) trong Python 2.7 bằng cách sử dụng cPickle.dumps()và giải nén trong Python 3 với pickle.loads(..., encoding='latin1')hoạt động tốt.
djvg

@djvg Tôi gặp phải vấn đề khi phải chọn hình ảnh dưới dạng chuỗi hình ảnh và giải nén chúng. Mã có thể được tìm thấy ở đây. gist.github.com/sreeragh-ar/70205db3a43badbfa69f758faa898be3
Sreeragh AR

@Gulzar Xin vui lòng xem ý chính ở trên cho vấn đề. Hình ảnh đã bị hỏng sau khi giải nén.
Sreeragh AR
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.