Python 3 ile bir python 2 nesnesinin ayıklanması


129

Python 3.4 ile Python 2.4'te salamura edilmiş bir nesneyi yüklemenin bir yolu olup olmadığını merak ediyorum.

Güncellemek için büyük miktarda eski şirket kodu üzerinde 2to3 çalıştırıyorum.

Bunu yaptıktan sonra, dosyayı çalıştırırken aşağıdaki hatayı alıyorum:

  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)

Turşu nesnesine çekişme içinde bakıldığında, a dictiçinde dict, türün anahtarlarını ve değerlerini içerir str.

Öyleyse sorum şu: Python 3.4 ile orijinal olarak python 2.4'te turşu haline getirilmiş bir nesneyi yüklemenin bir yolu var mı?


1
Python 2.4 jsonmodüle sahip mi? Belki nesneyi çözen ve bir json nesnesi olarak kaydeden bir 2.4 komut dosyası yazabilir ve ardından json nesnesini okuyan ve onu 3.4 uyumlu bir turşu nesnesi olarak kaydeden bir 3.4 komut dosyası yazabilirsiniz. Bu, tüm turşu dosyalarınızda çalıştırdığınız tek seferlik bir işlem olacaktır.
Kevin

Ben de benzer çizgiler üzerinde düşünüyordum, sys.stdout'u bir dosyaya değiştirip yazdırabileceğimi sanıyorum, ama önce onları yükleyip yükleyemeyeceğimi görmek istiyorum
NDevox

Özellikle veri zamanlarıyla ilgili soru: stackoverflow.com/questions/24805105/…
John Y

Yanıtlar:


189

pickle.load()Python'u test ederek verileri Python 3 dizelerine nasıl dönüştüreceğinizi söylemeniz gerekecek veya picklebunları bayt olarak bırakmayı söyleyebilirsiniz .

Varsayılan, tüm dize verilerini ASCII olarak denemek ve çözmektir ve bu kod çözme başarısız olur. pickle.load()Belgelere bakın :

İsteğe bağlı anahtar kelime argümanları, Python 2 tarafından oluşturulan turşu akışı için uyumluluk desteğini kontrol etmek için kullanılan fix_imports , kodlama ve hatalardır. Fix_imports doğruysa, pickle eski Python 2 adlarını Python 3'te kullanılan yeni adlarla eşleştirmeye çalışacaktır. kodlama ve hatalar pickle'a Python 2 tarafından seçilen 8 bitlik dize örneklerinin nasıl çözüleceğini söyler; bunlar varsayılan olarak "ASCII" ve "katı" dır. Kodlama bayt nesneler olarak, bu 8-bit dizisi örneklerini almak için 'bayt' olabilir.

Kodlamayı latin1, verileri doğrudan içe aktarmanıza izin verecek şekilde ayarlamak :

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

ancak dizelerinizden hiçbirinin yanlış codec kullanılarak kodunun çözülmediğini doğrulamanız gerekir; Latin-1, 0-255 bayt değerlerini doğrudan ilk 256 Unicode kod noktasına eşlediği için herhangi bir girdi için çalışır.

Alternatif, verileri yüklemek encoding='bytes've tümünün kodunu çözmek olabilir.bytes ve daha sonra anahtarların ve değerlerin .

3.6.8, 3.7.2 ve 3.8.0'dan önceki Python sürümlerine kadar, kullanmadığınız sürece Python 2 datetimenesne verilerinin çözülmesinin bozulduğunu unutmayın encoding='bytes'.


1
Bu nasıl Python 2 ile geriye dönük uyumlu hale getirilebilir? Görünüşe göre, kodlama bağımsız değişkeni Python 2 için mevcut değil.
EpicAdv

2
@EpicAdv: Bu kodu Python 2 ile uyumlu hale getirmenize gerek yok; bu soru Python 2 turşularını Python 3'e nasıl yükleyeceğinizle ilgilidir. Python 2 için encodinganahtar kelimeyi tamamen bırakın .
Martijn Pieters

10
@EpicAdv: python 2 için boş olan bir pickle_options sözlüğü oluşturabilir veya 'encoding': 'latin1'pickle için ** pickle_options içeren ve gönderebilirsiniz. Bu şekilde her iki versiyonda da çalışmalıdır.
pipefish

@pipefish - Zekice, ancak bir yerde hangi sürümü kullandığınızı tespit etmeniz gerekiyor, böylece aramayı daha basit bir şekilde, sürüme bağlı olarak farklı şekilde (biri ekstra argümanlı ve diğeri ekstra argüman olmadan) yapabilirsiniz. Ama en azından, Martijn'in yorumunun hiç ele almadığı EpicAdv yorumunun özüne sahipsin.
John Y

2
datetimeYorumun bu cevabın ana itici gücü olmadığının farkındayım , ancak gelecekteki okuyucular için, Python 3'ün "sabit" sürümlerinin bile encoding='latin-1'Python 2 veri zamanlarının kaldırılmasını gerektirdiğini belirtmek isterim . Turşu Python 2 verileriniz hem veri zamanlarını hem de Latin-1'den farklı bir şekilde kodlanmış bytestrings içeriyorsa, o zaman yine de kullanmanız daha iyi olabilir encoding='bytes'.
John Y

15

Kullanmak encoding='latin1', nesneniz içinde uyuşmuş diziler içerdiğinde bazı sorunlara neden olur.

Kullanmak encoding='bytes'daha iyi olacak.

Kullanımın tam açıklaması için lütfen bu yanıta bakınencoding='bytes'


Hangi sorunlar? Nelere dikkat etmeliyim? kullanmak bytesdizeleri bayt () haline getirir, bu yüzden latin1mümkünse tercih ederim , ancak sorunun ne olduğu benim için net değil.
Gulzar

2
@ sreeragh-ar: Karşılaştığınız sorunlara bir örnek verebilir misiniz? numpy.ndarrayPython 2.7'de iki boyutlu (numpy 1.14) salamura sahibim cPickle.dumps()ve Python 3'te pickle.loads(..., encoding='latin1')iyi çalışıyor.
djvg

@djvg Görüntüleri görüntü dizesi olarak seçip çözmem gerektiğinde sorunlarla karşılaştım. Kod burada bulunabilir. gist.github.com/sreeragh-ar/70205db3a43badbfa69f758faa898be3
Sreeragh AR

@Gulzar Lütfen sorunun özüne bakın. Çıkartıldıktan sonra görüntüler bozulmuştu.
Sreeragh AR
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.