Próbowałem zbudować ten obiekt bajtów w Pythonie 3:
b'3\r\n'
więc wypróbowałem oczywiste (dla mnie) i znalazłem dziwne zachowanie:
>>> bytes(3) + b'\r\n'
b'\x00\x00\x00\r\n'
Widocznie:
>>> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Nie udało mi się znaleźć żadnych wskazówek, dlaczego konwersja bajtów działa w ten sposób, czytając dokumentację. Jednak w tym numerze Pythona znalazłem niespodziewane komunikaty dotyczące dodawania format
do bajtów (zobacz także formatowanie 3 bajtów w Pythonie ):
http://bugs.python.org/issue3982
To współdziała teraz jeszcze gorzej z dziwactwami, takimi jak bajty (int) zwracające zera
i:
Byłoby dla mnie o wiele wygodniejsze, gdyby bytes (int) zwróciło ASCIIfication tego int; ale szczerze, nawet błąd byłby lepszy niż to zachowanie. (Gdybym chciał tego zachowania - którego nigdy nie miałem - wolałbym, żeby to była metoda klasowa, wywoływana jak „bytes.zeroes (n)”.)
Czy ktoś może mi wyjaśnić, skąd bierze się to zachowanie?
źródło
3 .to_bytes
Odpowiedzi:
W ten sposób został zaprojektowany - i ma to sens, ponieważ zwykle wywołujesz
bytes
iterowalną zamiast pojedynczej liczby całkowitej:Dokumentacja to stwierdza , a także dokumentacja
bytes
:źródło
bytes
to tylko alias dlastr
, co oznacza,bytes([3])
że daje'[3]'
.bytes([n])
działa tylko dla int n od 0 do 255. W przypadku czegokolwiek innego podnosiValueError
.bytes([3])
nadal różni się od tego, czego chciał OP - a mianowicie wartości bajtu używanej do zakodowania cyfry „3” w ASCII, tj.bytes([51])
czylib'3'
nieb'\x03'
.bytes(500)
tworzy bajtest z / len == 500. Nie tworzy bajtestu, który koduje liczbę całkowitą 500. I zgadzam się, żebytes([500])
to nie może działać, dlatego też jest to zła odpowiedź. Prawdopodobnie prawidłowa odpowiedź toint.to_bytes()
wersja> = 3.1.Od Pythona 3.2 możesz to zrobić
https://docs.python.org/3/library/stdtypes.html#int.to_bytes
W związku z tym
x == int_from_bytes(int_to_bytes(x))
. Zauważ, że to kodowanie działa tylko dla liczb całkowitych bez znaku (nieujemnych).źródło
b"3"
od3
, jak zagadnienie pyta. (To dab"\x03"
.)Możesz użyć paczki struktury :
„>” To kolejność bajtów (big-endian), a „I” to znak formatu . Możesz więc być konkretny, jeśli chcesz zrobić coś innego:
Działa to tak samo na Pythonie 2 i Pythonie 3 .
Uwaga: operację odwrotną (bajty do int) można wykonać przy rozpakowywaniu .
źródło
I
,H
, iB
praca aż2**k - 1
gdzie k jest 32, 16 i 8 odpowiednio. W przypadku większych nakładów podnosząstruct.error
.b'3\r\n'
, czyli bajt łańcuch zawierający znak ASCII „3” a nie znaków ASCII „\ X03”\x03
, a rozwiązanie, jeśli chcesz po prostub'3'
jest trywialne. Powód przytoczony przez ABB jest znacznie bardziej prawdopodobny ... lub przynajmniej zrozumiały.bytes([x])
i(x).to_bytes()
w Pythonie 3.5. To było niespodziewane.Python 3.5+ wprowadza interpolację% (
printf
formatowanie stylu) dla bajtów :Zobacz PEP 0461 - Dodawanie formatowania% do bajtów i bajtów .
We wcześniejszych wersjach możesz użyć
str
i.encode('ascii')
wynik:Uwaga: różni się od tego, co
int.to_bytes
produkuje :źródło
Dokumentacja mówi:
Sekwencja:
Jest to znak „3” (dziesiętnie 51), znak „\ r” (13) i „\ n” (10).
Dlatego sposób potraktowałby to jako takie, na przykład:
Przetestowano na IPythonie 1.1.0 i Pythonie 3.2.3
źródło
bytes(str(n), 'ascii') + b'\r\n'
lubstr(n).encode('ascii') + b'\r\n'
. Dzięki! :)"{}\r\n".format(n).encode()
nie sądzę, aby było coś złego przy użyciu domyślnego kodowania utf8ASCIIfication of 3
"\x33"
nie jest"\x03"
!Do tego służy Python
str(3)
ale byłoby to całkowicie błędne w przypadku bajtów, ponieważ powinny być traktowane jako tablice danych binarnych i nie powinny być nadużywane jako łańcuchy.Najłatwiejszym sposobem osiągnięcia tego, co chcesz, jest to
bytes((3,))
, co jest lepsze niżbytes([3])
inicjowanie listy jest znacznie droższe, więc nigdy nie używaj list, gdy możesz używać krotek. Możesz konwertować większe liczby całkowite za pomocąint.to_bytes(3, "little")
.Inicjalizacja bajtów o określonej długości ma sens i jest najbardziej przydatna, ponieważ często są używane do tworzenia pewnego typu bufora, dla którego potrzebujesz przydzielonej pamięci o podanym rozmiarze. Często używam tego podczas inicjowania tablic lub rozszerzania jakiegoś pliku przez zapisanie w nim zer.
źródło
b'3'
wiąże się kilka problemów: (a) Zapis ucieczki jestb'\x33'
, nieb'\x32'
. (b)(3)
nie jest krotką - musisz dodać przecinek. (c) Scenariusz inicjalizacji ciągu zerami nie dotyczybytes
obiektów, ponieważ są one niezmienne (ma to jednak sens dlabytearray
s).bytes
ibytearray
myślę, że jest to głównie kwestia spójności. Ale jest to również przydatne, jeśli chcesz wstawić kilka zer do bufora lub pliku, w którym to przypadku jest on używany tylko jako źródło danych.int
(w tym Python2long
) można przekonwertować nabytes
następującą funkcję:Odwrotną konwersję można wykonać inną:
Obie funkcje działają zarówno w Python2, jak i Python3.
źródło
Byłem ciekawy wydajności różnych metod dla pojedynczego int z zakresu
[0, 255]
, więc postanowiłem zrobić kilka testów czasowych.Na podstawie poniższych taktowania oraz od ogólnego trendu obserwowanego od I próbuje różne wartości i konfiguracje,
struct.pack
wydaje się być najszybszy, a następnieint.to_bytes
,bytes
izstr.encode
(nic dziwnego) jest najwolniejsze. Zwróć uwagę, że wyniki pokazują nieco więcej odchyleń niż przedstawiono,int.to_bytes
ibytes
czasami zmieniają ranking prędkości podczas testowania, alestruct.pack
jest wyraźnie najszybszy.Wyniki w CPython 3.7 w systemie Windows:
Moduł testowy (nazwany
int_to_byte.py
):źródło
[0, 255]
. Zakładam, że przez „zły wskaźnik” masz na myśli, że moje pomiary nie były wystarczająco ogólne, aby pasowały do większości sytuacji? A może moja metodologia pomiaru była słaba? Jeśli to drugie, chciałbym usłyszeć, co masz do powiedzenia, ale jeśli to pierwsze, nigdy nie twierdziłem, że moje pomiary są ogólne dla wszystkich przypadków użycia. W mojej (być może niszowej) sytuacji mam do czynienia tylko z intami z zakresu[0, 255]
, a to jest publiczność, do której zamierzałem się zwrócić za pomocą tej odpowiedzi. Czy moja odpowiedź była niejasna? Mogę to zmienić dla jasności ...bytes((i,))
zamiast tego,bytes([i])
ponieważ lista jest bardziej złożona, zużywa więcej pamięci i zajmuje dużo czasu na inicjalizację. W tym przypadku na nic.Chociaż wcześniejsza odpowiedź udzielona przez brunsgaarda jest wydajnym kodowaniem, działa tylko w przypadku liczb całkowitych bez znaku. Ten opiera się na nim, aby działał zarówno dla liczb całkowitych ze znakiem, jak i bez znaku.
W przypadku kodera
(i + ((i * signed) < 0)).bit_length()
jest używany zamiast tylkoi.bit_length()
dlatego, że ten ostatni prowadzi do nieefektywnego kodowania -128, -32768 itp.Kredyt: CervEd za naprawienie drobnej nieefektywności.
źródło
int_to_bytes(-128, signed=True) == (-128).to_bytes(1, byteorder="big", signed=True)
jestFalse
-128
,-32768
itd.(i+(signed*i<0)).bit_length()
Zachowanie wynika z faktu, że w Pythonie przed wersją 3
bytes
był tylko alias dlastr
. W Python3.xbytes
jest niezmienną wersjąbytearray
- zupełnie nowego typu, niekompatybilnego wstecz.źródło
Z dokumentów bajtów :
Następnie z dokumentów bytearray :
Zauważ, że różni się to od zachowania 2.x (gdzie x> = 6), gdzie
bytes
jest po prostustr
:PEP 3112 :
źródło
Niektóre odpowiedzi nie działają z dużymi liczbami.
Zamień liczbę całkowitą na reprezentację szesnastkową, a następnie zamień ją na bajty:
Wynik:
źródło
int.to_bytes
działa z dowolną liczbą całkowitą.Jeśli pytanie brzmi, jak przekonwertować samą liczbę całkowitą (a nie jej odpowiednik w postaci ciągu) na bajty, myślę, że solidna odpowiedź brzmi:
Więcej informacji o tych metodach tutaj:
źródło