Bir dize ve bir bayt dize arasındaki fark nedir?


213

Bayt dizesi döndüren bir kütüphane ile çalışıyorum ve bunu bir dizeye dönüştürmek gerekiyor.

Farkın ne olduğundan emin olmasam da - eğer varsa.

Yanıtlar:


263

Python 3 varsayarsak (Python 2'de bu fark biraz daha az iyi tanımlanmıştır) - dize bir karakter dizisidir, yani unicode kod noktaları ; bunlar soyut bir kavramdır ve doğrudan diskte depolanamaz. Bir bayt dizisi, dizisidir, beklendiği üzere bayt - şeyleri yapabilirsiniz diskte depolanabilir. Aralarındaki eşleme bir kodlamadır - bunlardan çok fazla vardır (ve sonsuz sayıda mümkündür) - ve dönüşümü yapmak için belirli bir durumda hangisinin geçerli olduğunu bilmeniz gerekir, çünkü farklı bir kodlama aynı baytları eşleyebilir farklı bir dizeye:

>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-16')
'蓏콯캁澽苏'
>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-8')
'τoρνoς'

Hangisini kullanacağınızı öğrendikten sonra .decode(), yukarıdaki gibi doğru karakter dizesini almak için bayt dizesinin yöntemini kullanabilirsiniz . Tamlık için .encode(), bir karakter dizesinin yöntemi tam tersine gider:

>>> 'τoρνoς'.encode('utf-8')
b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'

7
Python 2 kullanıcılarına açıklık getirmek için: strtür, türle aynıdır bytes; bu cevap, unicodetürü (Python 3'te yoktur) tür ile eşdeğer olarak karşılaştırır str.
craymichael

3
@KshitijSaraogi de bu doğru değil; bütün cümle düzenlendi ve biraz talihsiz. Python 3 strnesnelerinin bellek içi gösterimine Python tarafından erişilemez veya ilgili değildir; veri yapısı sadece bir kod noktası dizisidir. PEP 393 altında , tam dahili kodlama Latin-1, UCS2 veya UCS4'ten biridir ve bir utf-8 gösterimi ilk istendikten sonra önbelleğe alınabilir, ancak C kodu bile bu dahili detaylara güvenmekten vazgeçirilebilir.
lvc

1
Doğrudan diskte depolanamıyorlarsa, bellekte nasıl saklanırlar?
z33k

2
@orety onlar kodlanmış zorunda nedense tam olarak bu nedenden dolayı içten, ama bu değil sen kayan noktalı sayılar depolandığı nasıl umurumda gerekmez çok gibi Python kodundan size expos3s.
lvc

1
@ChrisStryczynski yukarıdaki yorumları görüyorlar - bir şekilde hafızada saklandıklarından emin olun , ancak bu form açıkça soyutlandı. Gerçekten de, bu günlerde, bir programın ömrü boyunca değişebilir ve farklı dizeler arasında farklı olabilir veya hatta karakterlere bağlı olarak birden fazla (bazı kodlamalar önbelleğe alınır) olabilir - ancak endişelenmeniz gereken tek zaman dize türünün kendisinin uygulanmasını hack ediyorsanız.
lvc

394

Bir bilgisayarın depolayabileceği tek şey bayttır.

Bilgisayarda herhangi bir şey saklamak için önce onu kodlamanız , yani bayta dönüştürmeniz gerekir. Örneğin:

  • Müzik saklamak istiyorsanız, önce gereken kodlamak kullanarak MP3, WAVvb
  • Bir resim saklamak istiyorsanız, önce gereken kodlamak kullanarak PNG, JPEGvb
  • Metni saklamak istiyorsanız, önce gereken kodlamak kullanarak ASCII, UTF-8vb

MP3, WAV, PNG, JPEG, ASCIIVe UTF-8örnek olarak kodlama . Kodlama, sesi, görüntüleri, metni vb. Bayt cinsinden temsil eden bir formattır.

Python'da bir bayt dizesi sadece şudur: bir bayt dizisi. İnsan tarafından okunabilir değil. Kaputun altında, her şey bir bilgisayarda saklanmadan önce bir bayt dizesine dönüştürülmelidir.

Öte yandan, genellikle "dize" olarak adlandırılan bir karakter dizesi bir karakter dizisidir. İnsan tarafından okunabilir. Bir karakter dizisi doğrudan bir bilgisayarda saklanamaz, önce kodlanması gerekir (bayt dizesine dönüştürülür). Bir karakter dizesinin ASCIIve gibi bir bayt dizesine dönüştürülebileceği birden çok kodlama vardır UTF-8.

'I am a string'.encode('ASCII')

Yukarıdaki Python kodu, kodlamayı 'I am a string'kullanarak dizeyi kodlayacaktır ASCII. Yukarıdaki kodun sonucu bir bayt dizesi olacaktır. Yazdırırsanız, Python bunu temsil edecektir b'I am a string'. Bununla birlikte, bayt dizelerinin insan tarafından okunamayacağını , sadece Python'un bunları ASCIIyazdırdığınızda çözdüğünü unutmayın. Python'da, bir bayt dizesi a ile b, ardından bayt dizesinin ASCIItemsiliyle temsil edilir.

Bir bayt dizesi, onu kodlamak için kullanılan kodlamayı biliyorsanız, bir karakter dizesine geri deşifre edilebilir .

b'I am a string'.decode('ASCII')

Yukarıdaki kod orijinal dizeyi döndürür 'I am a string'.

Kodlama ve kod çözme ters işlemdir. Her şey diske yazılmadan önce kodlanmalı ve bir insan tarafından okunmadan önce deşifre edilmesi gerekir.


60
Zenadix burada bazı kudosları hak ediyor. Bu ortamda çalıştıktan birkaç yıl sonra, benimle tıklayan ilk açıklama onun oldu. Diğer kolumda dövme yapabilirim (bir kol zaten "Mutlak Minimum Her Yazılım Geliştiricisi Joel
Spolsky

4
Kesinlikle harika. Berrak ve anlaşılması kolay. Ancak, bu çizgiden bahsetmek isterim - "Yazdırırsanız, Python bunu b'I dize olarak temsil eder '", Python2 bayt ve str için olduğu gibi Python3 için de geçerlidir.
SRC

5
Bu konuya biraz açıklık getirmek için insan tarafından okunabilir bir açıklama sunduğunuz için bu ödülünüzü ödüllendiriyorum!
fedorqui 'SO

3
Mükemmel cevap. Belki de eklenebilecek tek şey, tarihsel olarak, programcıların ve programlama dillerinin bir bayt dizisinin ve bir ASCII dizesinin aynı şey olduğunu açıkça veya örtük olarak varsayma eğiliminde olduklarını daha açık bir şekilde belirtmektir . Python 3 bu varsayımı açıkça doğrulamaya karar verdi, doğru IMHO.
nekomatic

4
Yukarıdaki @ neil.millikin tarafından bahsedilen Joel'in gönderisine bağlantı: joelonsoftware.com/2003/10/08/…
Kshitij Saraogi

14

Not: Python 2'nin ömrünün sonuna çok yakın olduğu için Python 3 için cevabımı daha ayrıntılı olarak açıklayacağım.

Python 3'te

bytes8 bit işaretsiz değerlerin strdizilerinden oluşurken, insan dillerindeki metin karakterlerini temsil eden Unicode kod noktalarının dizilerinden oluşur.

>>> # bytes
>>> b = b'h\x65llo'
>>> type(b)
<class 'bytes'>
>>> list(b)
[104, 101, 108, 108, 111]
>>> print(b)
b'hello'
>>>
>>> # str
>>> s = 'nai\u0308ve'
>>> type(s)
<class 'str'>
>>> list(s)
['n', 'a', 'i', '̈', 'v', 'e']
>>> print(s)
naïve

Olsa bytesve straynı şekilde çalışır gibi görünüyor, onların örneklerini yani birbirleri ile uyumlu değildir, bytesve strörnekleri gibi operatörleri ile birlikte kullanılamaz >ve +. Ayrıca, karşılaştırma bytesve streşitlik için örneklerin, yani kullanımın ==, Falsetam olarak aynı karakterleri içerdiklerinde bile her zaman değerlendireceğini unutmayın .

>>> # concatenation
>>> b'hi' + b'bye' # this is possible
b'hibye'
>>> 'hi' + 'bye' # this is also possible
'hibye'
>>> b'hi' + 'bye' # this will fail
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat str to bytes
>>> 'hi' + b'bye' # this will also fail
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "bytes") to str
>>>
>>> # comparison
>>> b'red' > b'blue' # this is possible
True
>>> 'red'> 'blue' # this is also possible
True
>>> b'red' > 'blue' # you can't compare bytes with str
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'bytes' and 'str'
>>> 'red' > b'blue' # you can't compare str with bytes
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'str' and 'bytes'
>>> b'blue' == 'red' # equality between str and bytes always evaluates to False
False
>>> b'blue' == 'blue' # equality between str and bytes always evaluates to False
False

Yerleşik işlev kullanılarak döndürülen dosyalarla çalışırken bytesve çalışırken başka bir sorun var . Bir yandan, bir dosyaya ikili veri okumak veya yazmak istiyorsanız, dosyayı her zaman 'rb' veya 'wb' gibi bir ikili mod kullanarak açın. Öte yandan, bir dosyaya / dosyasından Unicode veri okumak veya yazmak istiyorsanız, bilgisayarınızın varsayılan kodlamasının farkında olun, bu yüzden gerekirse sürprizlerden kaçınmak için parametreyi geçin.stropenencoding

Python 2'de

str8 bitlik değer unicodedizilerinden oluşur, Unicode karakter dizilerinden oluşur. Akılda tutulması gereken bir şey, strve sadece 7 bit ASCI karakterlerinden oluşuyorsa unicodeişleçlerle birlikte kullanılabileceğidir str.

Arasına dönüştürmek için yardımcı işlevlerini kullanmak yararlı olabilir strve unicodePython 2'de ve aralarında bytesve strPython 3'te.


4

Gönderen Unicode nedir :

Temel olarak, bilgisayarlar sadece sayılarla ilgilenir. Her biri için bir sayı atayarak harfleri ve diğer karakterleri saklarlar.

......

Unicode, platform ne olursa olsun, program ne olursa olsun, dil ne olursa olsun her karakter için benzersiz bir sayı sağlar.

Bir bilgisayar bir dizeyi temsil ettiğinde, dizenin bilgisayarında depolanan karakterleri benzersiz Unicode numaraları aracılığıyla bulur ve bu rakamlar bellekte depolanır. Ancak dizeyi doğrudan diske yazamaz veya dizeyi benzersiz Unicode numaraları aracılığıyla ağ üzerinde iletemezsiniz, çünkü bu rakamlar sadece basit ondalık sayıdır. Dizeyi, bayt dizesi gibi kodlamanız gerekir UTF-8. UTF-8tüm olası karakterleri kodlama yeteneğine sahip kodlayan bir karakterdir ve bayt (benziyor gibi karakterleri saklayan bu ). Böylece kodlanmış dize her yerde kullanılabilir çünkü UTF-8neredeyse her yerde desteklenir. Kodlanmış bir metin dosyasını açtığınızdaUTF-8diğer sistemlerden, bilgisayarınız onu çözer ve benzersiz Unicode numaraları aracılığıyla içindeki karakterleri görüntüler. Bir tarayıcı UTF-8ağdan kodlanmış dize verisi aldığında , verinin kodunu çözer ( UTF-8kodlamanın tarayıcıda olduğunu varsayar ) ve dizeyi görüntüler.

Python3 içinde, dizeyi ve bayt dizesini birbirine dönüştürebilirsiniz:

>>> print('中文'.encode('utf-8'))
b'\xe4\xb8\xad\xe6\x96\x87'
>>> print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8'))
中文 

Tek kelimeyle, dize bir bilgisayarda okumak için insanlara göstermek için ve bayt dize disk ve veri iletiminde saklamak içindir.


1

Unicode, karakterlerin ve çeşitli biçimlendirme türlerinin (örn. Küçük harf / büyük harf, yeni satır, satır başı) ve diğer "şeylerin (örn. Emojiler) ikili gösterimi için üzerinde anlaşmaya varılmış bir biçimdir. Bilgisayar, ister bellekte ister dosyada olsun, bir unicode temsilini (bir dizi bit) depolamak için bir ascii temsilini (farklı bir bit dizisi) veya başka bir temsili (bit dizisi) depolamaktan daha az yetenekli değildir. ).

İçin iletişim gerçekleşmesi, iletişim taraf kullanılacaktır neler temsil katılıyorum gerekir.

Unicode, insanlar arası ve bilgisayarlararası iletişimde kullanılan tüm olası karakterleri (ve diğer "şeyleri") temsil etmeye çalıştığından, diğer temsil sistemlerinden daha fazla karakterin (veya nesnenin) gösterilmesi için daha fazla sayıda bit gerektirir. daha sınırlı sayıda karakter / şeyi temsil etmeye çalışın. "Basitleştirmek" ve belki de tarihsel kullanıma uyum sağlamak için, unicode gösterimi karakterleri dosyalarda saklamak amacıyla neredeyse tamamen başka bir temsil sistemine (örneğin ascii) dönüştürülür.

Bu unicode Eğer durum değildir olamaz dosyalarında karakterleri depolamak ya yoluyla iletmek için kullanılacak herhangi basitçe o, iletişim kanalı olduğunu değil.

"String" terimi tam olarak tanımlanmamıştır. "String", ortak kullanımında bir dizi karakter / şeyi ifade eder. Bir bilgisayarda, bu karakterler birçok farklı uçtan uca gösterimden birinde depolanabilir. "Bayt dizesi", sekiz bit (sekiz bit bayt olarak adlandırılır) kullanan bir gösterim kullanılarak depolanan bir karakter kümesidir. Bu günlerde bilgisayarlar karakterleri bellekte saklamak için unicode sistemini (değişken sayıda baytla temsil edilen karakterler) ve karakterleri dosyalara depolamak için bayt dizelerini (tek baytla temsil edilen karakterler) kullandığından, temsil edilen karakterlerden önce bir dönüşüm kullanılmalıdır bellekte dosyalarda depoya taşınacaktır.


0

Basit bir tek karakterli dize alalım 'š've bunu bir bayt dizisine kodlayalım:

>>> 'š'.encode('utf-8')
b'\xc5\xa1'

Bu örneğin amacı için bayt dizisini ikili biçimde gösterelim:

>>> bin(int(b'\xc5\xa1'.hex(), 16))
'0b1100010110100001'

Şimdi, nasıl kodlandığını bilmeden bilgilerin şifresini çözmek genellikle mümkün değildir . Yalnızca utf-8metin kodlamasının kullanıldığını biliyorsanız, utf-8 kodunu çözmek için algoritmayı takip edebilir ve orijinal dizeyi edinebilirsiniz:

11000101 10100001
   ^^^^^   ^^^^^^
   00101   100001

İkili sayıyı 101100001bir dize olarak geri görüntüleyebilirsiniz :

>>> chr(int('101100001', 2))
'š'

0

Python dilleri içerir strve bytesstandart olarak "Yerleşik türleri". Başka bir deyişle, her ikisi de sınıftır. Python'un neden bu şekilde uygulandığını rasyonelleştirmeye çalışmak gerektiğini düşünmüyorum.

Bunu söyledikten strve bytesbirbirine çok benzer. Her ikisi de aynı yöntemlerin çoğunu paylaşır. Aşağıdaki yöntemler strsınıfa özgüdür :

casefold
encode
format
format_map
isdecimal
isidentifier
isnumeric
isprintable

Aşağıdaki yöntemler bytessınıfa özgüdür :

decode
fromhex
hex
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.