Python 3'te dizgiyi bayta dönüştürmenin en iyi yolu?


860

Bir dizeyi baytlara dönüştürmenin iki farklı yolu var gibi görünüyor, TypeError yanıtlarında görüldüğü gibi : 'str' arabellek arayüzünü desteklemiyor

Bu yöntemlerden hangisi daha iyi veya daha fazla Pythonic olurdu? Yoksa bu sadece kişisel bir tercih midir?

b = bytes(mystring, 'utf-8')

b = mystring.encode('utf-8')

42
Kodlama / kod çözme kullanımı daha yaygın ve belki de daha nettir.
Lennart Regebro

11
@LennartRegebro İşten çıkarıyorum. Daha yaygın olsa bile, "bytes ()" okumak ne yaptığını biliyorum, encode () bana bayt kodlama hissediyorum yapmıyorum.
m3nda

2
@ o kadar kullanmak için iyi bir nedendir erm3nda gelmez , o zaman ki gibi hissediyorum bir adım daha yakın Unicode zen için.
Lennart Regebro

3
@LennartRegebro Sadece kullanmak için yeterince iyi hissediyorum bytes(item, "utf8"), çünkü açık, örtükten daha iyidir, bu yüzden ... str.encode( )varsayılan olarak baytlara sessizce geçer, sizi daha fazla Unicode-zen ama daha az Açık-Zen yapar. Ayrıca "ortak" takip etmek istediğim bir terim değil. Ayrıca, bytes(item, "utf8")daha çok str(), ve b"string"gösterimler gibidir. Benim özür dilerim ben nedenlerini anlamak için çok çaylak. Teşekkür ederim.
m3nda

4
@ erm3nda Eğer kabul encode()etmediğin cevabı okuduysan aramazsın, tam tersi bytes(). Tabii ki bu hemen belli değil, bu yüzden soruyu sordum.
Mark Ransom

Yanıtlar:


571

İçin dokümanlara bakarsanız, sizi şu bytesnoktalara yönlendirir bytearray:

bytearray ([kaynak [, kodlama [, hatalar]]])

Yeni bir bayt dizisi döndürür. Bytearray tipi, 0 <= x <256 aralığındaki değişebilir bir tamsayı dizisidir. Değişken Dizi Tiplerinde açıklanan olağan değişebilir dizi yöntemlerinin yanı sıra bayt tipinin sahip olduğu yöntemlerin çoğuna sahiptir, Bayt ve Bayt Dizisi Yöntemleri.

İsteğe bağlı source parametresi, diziyi birkaç farklı şekilde başlatmak için kullanılabilir:

Bir dize ise, kodlama (ve isteğe bağlı olarak hatalar) parametrelerini de vermelisiniz; bytearray () daha sonra dizeyi str.encode () kullanarak bayta dönüştürür.

Bir tamsayı ise, dizi bu boyuta sahip olur ve boş baytlarla başlatılır.

Arabellek arayüzüne uyan bir nesne ise, bayt dizisini başlatmak için nesnenin salt okunur bir tamponu kullanılır.

Yinelenebilirse, dizinin ilk içeriği olarak kullanılan 0 <= x <256 aralığında bir tamsayı yinelenebilir olmalıdır.

Bağımsız değişken olmadan, 0 boyutunda bir dizi oluşturulur.

Yani bytesbir dizeyi kodlamaktan çok daha fazlasını yapabilir. Yapıcıyı mantıklı herhangi bir kaynak parametresi türüyle çağırmanıza izin vermesi Pythonic'tir.

Bir dize kodlamak için, ben some_string.encode(encoding)bu yapıcı kullanmak daha Pythonic olduğunu düşünüyorum , çünkü en kendi kendine belgeleme - "Bu dize almak ve bu kodlama ile kodlamak" daha açık bytes(some_string, encoding)- kullandığınızda hiçbir açık fiil yok yapıcı.

Düzenleme: Python kaynağını kontrol ettim. bytesCPython kullanarak bir unicode dizesi iletirseniz , bunun uygulanması olan PyUnicode_AsEncodedString öğesini çağırır encode; yani, encodekendinizi ararsanız, sadece bir dolaylı aktarım seviyesini atlıyorsunuz demektir .

Ayrıca, Serdalis'in yorumuna da bakınız - unicode_string.encode(encoding)tersi byte_string.decode(encoding)ve simetri güzel olduğu için daha Pitoniktir .


73
Python belgelerinden iyi bir tartışma ve alıntılar için +1. Ayrıca dizenizi geri istediğinizde unicode_string.encode(encoding)güzel eşleşir bytearray.decode(encoding).
Serdalis

6
bytearraydeğiştirilebilir bir nesneye ihtiyacınız olduğunda kullanılır. Basit için buna ihtiyacı yoktur strbytesdönüşümler.
hamstergene

8
@EugeneHomyakov Bunun ile ilgili bir şey yok, bytearraybunun için dokümanlar bytesayrıntı vermiyorlar, sadece "bu değişmez bir versiyonudur" derler, bu bytearrayyüzden oradan alıntı yapmalıyım.
agf

1
Sadece uyarı notu Özetle içinde Python hakkında bytesbir tamsayı bağımsız değişkenle bir fonksiyonu olarak bayt türünü kullanarak kaçının. V2'de bu, (bayt) bir dizeye dönüştürülen tamsayıyı döndürür, çünkü baytlar str için bir takma addır, v3'te ise belirtilen sayıda boş karakter içeren bir bytestring döndürür. Bu nedenle, örneğin, v3 ifade baytları (6) yerine, her sürümde aynı şekilde çalışan b '\ x00' * 6 eşdeğerini kullanın.
holdenweb

2
Eğer bir dizeye ikili veri dönüştürmek için çalışıyorsanız, use şey büyük olasılıkla ihtiyaç olacak gibi, sadece Not, byte_string.decode('latin-1')olarak utf-8piton kontrol, tüm aralığı 0xFF 0x00 (0-255) kapsamaz dokümanlar için Daha fazla bilgi.
iggy12345

348

Düşündüğünden daha kolay:

my_str = "hello world"
my_str_as_bytes = str.encode(my_str)
type(my_str_as_bytes) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
type(my_decoded_str) # ensure it is string representation

37
Bunu nasıl yapacağını biliyor, sadece hangi yolun daha iyi olduğunu soruyor. Lütfen soruyu tekrar okuyun.
agf

30
FYI: str.decode (bayt) benim için işe yaramadı (Python 3.3.3 "tür nesnesi" str "'decode'" özniteliğine sahip değil dedi) Onun yerine bytes.decode () kullandım
Mike

6
@ Mike: Kullanım obj.method()sözdizimi yerine cls.method(obj)sözdizimi yani kullanım bytestring = unicode_text.encode(encoding)ve unicode_text = bytestring.decode(encoding).
jfs

2
... yani gereksiz yere ilişkisiz bir yöntem yapıyorsunuz ve sonra bunu selfilk argüman olarak
geçiyorsunuz

2
@KolobCanyon Soru zaten bunu yapmanın doğru yolunu gösteriyor - encodedizede bağlı bir yöntem olarak adlandırın . Bu yanıt, bunun yerine bağlanmamış yöntemi çağırmanız ve dizeyi geçirmeniz gerektiğini gösterir. Cevaptaki tek yeni bilgi bu ve yanlış.
abarnert

144

Kesinlikle en iyi yolu ne 2'nin olmakla 3. Python 3.0'dan bu yana varsayılan olarak kullanılacak ilk parametre . Böylece en iyi yolencode 'utf-8'

b = mystring.encode()

Bu da daha hızlı olacaktır, çünkü varsayılan argüman "utf-8"C kodundaki dizede değil NULL, kontrol edilmesi çok daha hızlıdır!

İşte bazı zamanlamalar:

In [1]: %timeit -r 10 'abc'.encode('utf-8')
The slowest run took 38.07 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 183 ns per loop

In [2]: %timeit -r 10 'abc'.encode()
The slowest run took 27.34 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 137 ns per loop

Uyarısına rağmen, tekrarlanan çalışmalardan sonra süreler çok kararlıydı - sapma sadece yüzde ~ 2 idi.


encode()Bağımsız değişken olmadan kullanmak Python 2 ile uyumlu değildir, Python 2'de varsayılan karakter kodlaması ASCII'dir .

>>> 'äöä'.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

2
Burada sadece büyük bir fark var, çünkü (a) dize saf ASCII, yani dahili depolama zaten UTF-8 sürümü, bu yüzden codec'i aramak neredeyse tek maliyettir ve (b) dize küçüktür kodlamak zorunda olsanız bile çok fazla fark yaratmaz. Deneyin, diyelim ki '\u00012345'*10000. Her ikisi de dizüstü bilgisayarımda 28.8us alır; fazladan 50ns yuvarlama hatası nedeniyle kaybolur. Tabii ki bu oldukça aşırı bir örnek - ama 'abc'tam tersi gibi aşırı.
abarnert

@abarnert true, ancak o zaman bile, argümanı dize olarak iletmek için hiçbir neden yoktur.
Antti Haapala

Buna göre, varsayılan argümanlar her zaman bir şeyler yapmanın "kesinlikle en iyi yoludur", değil mi? Bu tür bir hız analizi, eğer C kodunu tartışmakla ilgiliyse, olası bir abartı gibi hissedecektir. Yorumlanan bir dilde, beni suskun bırakıyor.
hmijail
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.