Jak mogę przekonwertować ciąg bajtów na int w Pythonie?
Powiedz tak: 'y\xcc\xa6\xbb'
Wymyśliłem sprytny / głupi sposób na zrobienie tego:
sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))
Wiem, że musi być coś wbudowanego lub w standardowej bibliotece, które robi to prościej ...
Różni się to od konwersji ciągu cyfr szesnastkowych, dla których można użyć int (xxx, 16), ale zamiast tego chcę przekonwertować ciąg rzeczywistych wartości bajtów.
AKTUALIZACJA:
Odpowiedź Jamesa podoba mi się trochę lepiej, ponieważ nie wymaga importowania innego modułu, ale metoda Grega jest szybsza:
>>> from timeit import Timer
>>> Timer('struct.unpack("<L", "y\xcc\xa6\xbb")[0]', 'import struct').timeit()
0.36242198944091797
>>> Timer("int('y\xcc\xa6\xbb'.encode('hex'), 16)").timeit()
1.1432669162750244
Moja zhackowana metoda:
>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit()
2.8819329738616943
DALSZA AKTUALIZACJA:
Ktoś w komentarzach zapytał, jaki jest problem z importem innego modułu. Cóż, importowanie modułu niekoniecznie jest tanie, spójrz:
>>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit()
0.98822188377380371
Uwzględnienie kosztu importu modułu neguje prawie wszystkie zalety tej metody. Uważam, że będzie to obejmować koszt importu tylko raz na cały przebieg benchmarku; zobacz, co się dzieje, gdy za każdym razem zmuszam go do ponownego ładowania:
>>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit()
68.474128007888794
Nie trzeba dodawać, że jeśli wykonujesz wiele wykonań tej metody na jeden import, to staje się to proporcjonalnie mniejszym problemem. Prawdopodobnie jest to również koszt wejścia / wyjścia, a nie procesora, więc może to zależeć od pojemności i charakterystyki obciążenia konkretnej maszyny.
int.from_bytes
) jest lepsza niżstruct.unpack
na moim komputerze. Oprócz większej czytelności imo.Odpowiedzi:
Możesz również użyć modułu struct , aby to zrobić:
źródło
W Pythonie 3.2 i nowszych wersjach użyj
lub
zgodnie z endianness twojego ciągu bajtów.
Działa to również w przypadku liczb całkowitych z bajtowania o dowolnej długości i liczb całkowitych ze znakiem z uzupełnieniem do dwóch przez określenie
signed=True
. Zobacz dokumentację dlafrom_bytes
.źródło
os.urandom(4)
bajtów ** 1,4 µs ** (struct) vs ** 2,3 µs ** (int.from_bytes) na moim procesorze. python 3.5.2Jak powiedział Greg, możesz użyć struct, jeśli masz do czynienia z wartościami binarnymi, ale jeśli masz tylko „liczbę szesnastkową”, ale w formacie bajtowym, możesz po prostu przekonwertować ją na przykład:
... to jest to samo co:
... z wyjątkiem tego, że będzie działać dla dowolnej liczby bajtów.
źródło
int(''.join(reversed(s)).encode('hex'), 16)
Używam następującej funkcji do konwersji danych między int, hex i bajtami.
Źródło: http://opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html
źródło
Ostrzeżenie: powyższe informacje są ściśle związane z platformą. Zarówno specyfikator "I", jak i endianness konwersji string-> int są zależne od konkretnej implementacji Pythona. Ale jeśli chcesz przekonwertować wiele liczb całkowitych / ciągów na raz, moduł tablicy robi to szybko.
źródło
W Pythonie 2.x można użyć specyfikatorów formatu
<B
dla bajtów bez znaku i<b
bajtów ze znakiem zstruct.unpack
/struct.pack
.Na przykład:
Niech
x
='\xff\x10\x11'
I:
To
*
jest wymagane!Widzieć https://docs.python.org/2/library/struct.html#format-characters, aby uzyskać listę specyfikatorów formatu.
źródło
Test 1: odwrotny:
Test 2: Liczba bajtów> 8:
Test 3: Przyrost o jeden:
Test 4: Dołącz jeden bajt, powiedz „A”:
Test 5: Podziel przez 256:
Wynik jest równy wynikowi testu 4, zgodnie z oczekiwaniami.
źródło
Starałem się znaleźć rozwiązanie dla sekwencji bajtów o dowolnej długości, które działałyby pod Pythonem 2.x. Wreszcie napisałem ten, jest trochę hacky, ponieważ wykonuje konwersję ciągów, ale działa.
Funkcja dla Pythona 2.x, dowolna długość
Ta funkcja ma dwa wymagania:
Dane wejściowe
data
muszą mieć formatbytearray
. Możesz wywołać tę funkcję w ten sposób:Dane muszą być typu big-endian. Jeśli masz wartość little-endian, powinieneś najpierw ją odwrócić:
Oczywiście powinno to być używane tylko wtedy, gdy potrzebna jest dowolna długość. W przeciwnym razie trzymaj się bardziej standardowych sposobów (np
struct
.).źródło
int.from_bytes to najlepsze rozwiązanie, jeśli używasz wersji> = 3.2. Rozwiązanie „struct.unpack” wymaga łańcucha, więc nie będzie miało zastosowania do tablic bajtów. Oto inne rozwiązanie:
hex (bytes2int ([0x87, 0x65, 0x43, 0x21])) zwraca „0x87654321”.
Obsługuje duże i małe endianness i jest łatwo modyfikowalny do 8 bajtów
źródło
Jak wspomniano powyżej, użycie
unpack
funkcji struct jest dobrym sposobem. Jeśli chcesz zaimplementować własną funkcję to jest inne rozwiązanie:źródło
W Pythonie 3 można łatwo przekonwertować ciąg bajtów na listę liczb całkowitych (0..255) za pomocą
źródło
Przyzwoicie szybka metoda wykorzystująca array.array, której używam od jakiegoś czasu:
predefiniowane zmienne:
to int: (czytaj)
from int: (napisz)
Możliwe, że te mogą być szybsze.
EDYCJA:
W przypadku niektórych liczb, oto test wydajności (Anaconda 2.3.0) pokazujący stabilne średnie podczas odczytu w porównaniu z
reduce()
:To jest surowy test wydajności, więc endian pow-flip jest pomijany. Funkcja pokazano stosuje tę samą operację shift-oring jak dla pętli, i to tylko jak to ma najszybszy iteracyjny wydajność obok .
shift
arr
array.array('B',[0,0,255,0])
dict
Powinienem chyba również zauważyć, że efektywność mierzy się dokładnością do średniego czasu.
źródło