पाइथन 3 में बाइट्स में int परिवर्तित


177

मैं पायथन 3 में इस बाइट्स ऑब्जेक्ट को बनाने की कोशिश कर रहा था:

b'3\r\n'

इसलिए मैंने स्पष्ट (मेरे लिए) कोशिश की, और एक अजीब व्यवहार पाया:

>>> bytes(3) + b'\r\n'
b'\x00\x00\x00\r\n'

जाहिरा तौर पर:

>>> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

मैं किसी भी संकेत को देखने में असमर्थ रहा हूं कि बाइट्स रूपांतरण इस तरह से प्रलेखन को पढ़ने का काम क्यों करता है। हालाँकि, मुझे इस पायथन मुद्दे में formatबाइट्स में जोड़ने के कुछ आश्चर्यजनक संदेश मिले (देखें पायथन 3 बाइट्स स्वरूपण ):

http://bugs.python.org/issue3982

यह बाइट्स (इंट) जैसे विषमताओं के साथ और भी अधिक खराब तरीके से बातचीत करता है

तथा:

यह मेरे लिए बहुत अधिक सुविधाजनक होगा यदि बाइट्स (int) ने उस int का ASCIIfication लौटाया; लेकिन ईमानदारी से, यहां तक ​​कि एक त्रुटि भी इस व्यवहार से बेहतर होगी। (अगर मुझे यह व्यवहार चाहिए था - जो मेरे पास कभी नहीं था - तो मैं इसे एक क्लासमेथोड मानूंगा, जिसे "बाइट्स.जोरोज़ (एन)" की तरह लगाया जाएगा। "

क्या कोई मुझे समझा सकता है कि यह व्यवहार कहां से आता है?


1
शीर्षक से संबंधित:3 .to_bytes
JFS

2
यदि आप पूर्णांक मान 3, या ASCII वर्ण का प्रतिनिधित्व संख्या तीन (पूर्णांक मान 51) का मान चाहते हैं, तो यह आपके प्रश्न से स्पष्ट नहीं है। पहला बाइट्स ([3]) == b '\ x03' है। बाद वाला बाइट्स ([ord ('3')]) == b'3 'है।
फ्लोरिसला

जवाबों:


177

इस तरह से इसे डिजाइन किया गया था - और यह समझ में आता है क्योंकि आमतौर पर, आप bytesएक पूर्णांक के बजाय एक पुनरावृत्त पर कॉल करेंगे :

>>> bytes([3])
b'\x03'

डॉक्स इस राज्य है, साथ ही के लिए docstring bytes:

 >>> help(bytes)
 ...
 bytes(int) -> bytes object of size given by the parameter initialized with null bytes

25
खबरदार कि उपरोक्त केवल अजगर के साथ काम करता है 3. अजगर 2 bytesमें केवल एक उपनाम है str, जिसका अर्थ है bytes([3])कि आपको देता है '[3]'
botchniaque

8
पायथन 3 में, ध्यान दें कि bytes([n])केवल 0 से 255 तक int n के लिए काम करता है। किसी और चीज के लिए यह बढ़ जाता है ValueError
एक्यूमेनस

8
@ABB: वास्तव में आश्चर्य की बात नहीं है क्योंकि एक बाइट केवल 0 और 255 के बीच मूल्यों को संग्रहीत कर सकता है।
टिम पीटरसन

7
यह भी ध्यान दिया जाना चाहिए कि bytes([3])ओपी जो चाहता था उससे अभी भी अलग है - अर्थात् बाइट मान का उपयोग एएससीआईआई में अंक "3" को एन्कोड करने के लिए किया जाता है, अर्थात। bytes([51]), जो है b'3', नहीं b'\x03'
lenz

2
bytes(500)एक बाइटस्ट्रिंग w / len == 500 बनाता है। यह एक बाइटस्ट्रिंग नहीं बनाता है जो पूर्णांक 500 को एन्कोड करता है। और मैं मानता हूं कि bytes([500])यह काम नहीं कर सकता है, यही कारण है कि गलत उत्तर भी है। संभवतः सही उत्तर int.to_bytes()संस्करणों> = 3.1 के लिए है।
weberc2

198

अजगर 3.2 से आप कर सकते हैं

>>> (1024).to_bytes(2, byteorder='big')
b'\x04\x00'

https://docs.python.org/3/library/stdtypes.html#int.to_bytes

def int_to_bytes(x: int) -> bytes:
    return x.to_bytes((x.bit_length() + 7) // 8, 'big')

def int_from_bytes(xbytes: bytes) -> int:
    return int.from_bytes(xbytes, 'big')

तदनुसार, x == int_from_bytes(int_to_bytes(x))। ध्यान दें कि यह एन्कोडिंग केवल अहस्ताक्षरित (गैर-नकारात्मक) पूर्णांक के लिए काम करता है।


4
हालांकि यह उत्तर अच्छा है, यह केवल अहस्ताक्षरित (गैर-नकारात्मक) पूर्णांक के लिए काम करता है। मैंने अनुकूलित किया है यह एक उत्तर लिखता है जो हस्ताक्षरित पूर्णांक के लिए भी काम करता है।
एक्यूमेनस

1
जैसा कि सवाल पूछता है, b"3"से प्राप्त करने में मदद नहीं करता है 3। (यह दे देंगे b"\x03"।)
gsnedders

40

आप संरचना के पैक का उपयोग कर सकते हैं :

In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'

">" बाइट-ऑर्डर (बड़ा-एंडियन) है और "मैं" प्रारूप चरित्र है । यदि आप कुछ और करना चाहते हैं तो आप विशिष्ट हो सकते हैं:

In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'

In [13]: struct.pack("B", 1)
Out[13]: '\x01'

यह अजगर 2 और अजगर 3 दोनों पर समान काम करता है ।

नोट: उलटा ऑपरेशन (बाइट्स टू इंट) अनपैक के साथ किया जा सकता है ।


2
स्पष्ट करने के लिए, के बाद से एक struct इनपुट पर ध्यान दिए बिना एक मानक आकार है @AndyHayden, I, H, और Bजब तक काम 2**k - 1जहां k 32, 16, और 8 क्रमशः है। बड़े इनपुट के लिए वे उठाते हैं struct.error
एक्यूमेनस

संभवतया नीचे दिए गए वोट के रूप में यह सवाल का जवाब नहीं देता है: ओपी यह जानना चाहता है कि कैसे उत्पन्न किया जाए b'3\r\n', यानी बाइट्स-स्ट्रिंग जिसमें ASCII चरित्र "3" न कि ASCII चरित्र "\ x03"
डेव जोन्स

1
@DaveJones आपको क्या लगता है कि ओपी क्या चाहता है? स्वीकार किए जाते हैं जवाब रिटर्न \x03, और समाधान अगर आप सिर्फ चाहते b'3'तुच्छ है। एबीबी द्वारा उद्धृत कारण अधिक प्रशंसनीय है ... या कम से कम समझने योग्य है।
एंडी हेडन

@DaveJones इसके अलावा, मैंने यह उत्तर इसलिए जोड़ा क्योंकि Google इसे ठीक करने के लिए खोज करते समय आपको यहां ले जाता है। तो इसीलिए यहाँ है।
एंडी हेडन

4
न केवल 2 और 3 में यह काम करता है, बल्कि पायथन 3.5 में यह दोनों तरीकों bytes([x])और (x).to_bytes()तरीकों से तेज है । यह अनपेक्षित था।
मार्क रैनसम

25

पायथन 3.5+ printfबाइट्स के लिए % -प्रणाली (-स्टाइल प्रारूपण) का परिचय देता है :

>>> b'%d\r\n' % 3
b'3\r\n'

PEP 0461 देखें - बाइट्स और बायट्रेयर में% फ़ॉर्मेटिंग जोड़ना

पूर्व संस्करणों पर, आप उपयोग कर सकते हैं strऔर .encode('ascii')परिणाम:

>>> s = '%d\r\n' % 3
>>> s.encode('ascii')
b'3\r\n'

नोट: यह क्या int.to_bytesउत्पादन से अलग है :

>>> n = 3
>>> n.to_bytes((n.bit_length() + 7) // 8, 'big') or b'\0'
b'\x03'
>>> b'3' == b'\x33' != '\x03'
True

11

प्रलेखन कहता है:

bytes(int) -> bytes object of size given by the parameter
              initialized with null bytes

क्रम:

b'3\r\n'

यह वर्ण '3' (दशमलव 51) वर्ण '\ r' (13) और '\ n' (10) है।

इसलिए, उदाहरण के लिए, इसे इस तरह माना जाएगा:

>>> bytes([51, 13, 10])
b'3\r\n'

>>> bytes('3', 'utf8') + b'\r\n'
b'3\r\n'

>>> n = 3
>>> bytes(str(n), 'ascii') + b'\r\n'
b'3\r\n'

IPython 1.1.0 और पायथन 3.2.3 पर परीक्षण किया गया


1
मैंने करना समाप्त कर दिया bytes(str(n), 'ascii') + b'\r\n'या str(n).encode('ascii') + b'\r\n'। धन्यवाद! :)
एस्ट्रोजुनलू

1
@ Juanlu001, "{}\r\n".format(n).encode()मुझे भी नहीं लगता कि डिफ़ॉल्ट utf8 एन्कोडिंग का उपयोग करके कोई नुकसान हुआ है
जॉन ला रोय

6

3 का ASCIIfication "\x33"नहीं है "\x03"!

यह अजगर के लिए क्या करता है, str(3)लेकिन यह बाइट्स के लिए पूरी तरह से गलत होगा, क्योंकि उन्हें बाइनरी डेटा के सरणियों माना जाना चाहिए और स्ट्रिंग्स के रूप में दुरुपयोग नहीं किया जाना चाहिए।

आप bytes((3,))जो चाहते हैं उसे प्राप्त करने का सबसे आसान तरीका है , जो कि बेहतर है bytes([3])क्योंकि सूची को शुरू करना बहुत अधिक महंगा है, इसलिए जब आप ट्यूपल्स का उपयोग कर सकते हैं तो सूचियों का उपयोग कभी न करें। आप बड़े पूर्णांक का उपयोग करके परिवर्तित कर सकते हैं int.to_bytes(3, "little")

दी गई लंबाई के साथ बाइट्स को शुरू करना समझ में आता है और सबसे उपयोगी है, क्योंकि वे अक्सर कुछ प्रकार के बफर बनाने के लिए उपयोग किए जाते हैं, जिसके लिए आपको आवंटित आकार की कुछ मेमोरी की आवश्यकता होती है। मैं अक्सर इसका उपयोग तब करता हूं जब एरे को इनिशियलाइज़ करता है या कुछ फाइल को ज़ीरो लिखकर उसका विस्तार करता है।


1
इस उत्तर के साथ कई समस्याएं हैं: (ए) से बचने की धारणा b'3'है b'\x33', नहीं b'\x32'। (b) (3)कोई तुक नहीं है - आपको अल्पविराम जोड़ना होगा। (c) शून्य के साथ अनुक्रम को आरम्भ करने का परिदृश्य bytesवस्तुओं पर लागू नहीं होता , क्योंकि वे अपरिवर्तनीय हैं (यह bytearrays के लिए समझ में आता है , हालाँकि)।
लॉन्ज़

आपके कमेंट के लिए धन्यवाद। मैंने उन दो स्पष्ट गलतियों को तय किया। के मामले में bytesऔर bytearray, मुझे लगता है कि यह ज्यादातर स्थिरता की बात है। लेकिन यह भी उपयोगी है यदि आप कुछ शून्य को एक बफर या फ़ाइल में धकेलना चाहते हैं, तो उस स्थिति में इसका उपयोग केवल डेटा स्रोत के रूप में किया जाता है।
बछसौ

5

int(पायथन 2 सहित long) को bytesनिम्न फ़ंक्शन का उपयोग करके परिवर्तित किया जा सकता है:

import codecs

def int2bytes(i):
    hex_value = '{0:x}'.format(i)
    # make length of hex_value a multiple of two
    hex_value = '0' * (len(hex_value) % 2) + hex_value
    return codecs.decode(hex_value, 'hex_codec')

रिवर्स रूपांतरण एक दूसरे द्वारा किया जा सकता है:

import codecs
import six  # should be installed via 'pip install six'

long = six.integer_types[-1]

def bytes2int(b):
    return long(codecs.encode(b, 'hex_codec'), 16)

दोनों फ़ंक्शन पायथन 2 और पायथन 3 दोनों पर काम करते हैं।


'hex_value ='% x '% i' पायथन 3.4 के तहत काम नहीं करेगा। आपको एक TypeError मिलती है, इसलिए आपको इसके बजाय hex () का उपयोग करना होगा।
bjmc

@bjmc को str.format से बदल दिया गया। यह पायथन 2.6+ पर काम करना चाहिए।
renskiy

धन्यवाद, @renskiy आप 'हेक्स' के बजाय 'हेक्स_कोडेक' का उपयोग करना चाह सकते हैं क्योंकि ऐसा लगता है कि 'हेक्स' उर्फ ​​सभी पायथन 3 रिलीज पर उपलब्ध नहीं है, देखें stackoverflow.com/a/12917604/845210
bmmc

@bjmc तय धन्यवाद
renskiy

यह अजगर 3.6 पर नकारात्मक पूर्णांक पर विफल रहता है
Berserker

4

मैं रेंज में एक ही इंट के लिए विभिन्न तरीकों के प्रदर्शन के बारे में उत्सुक था [0, 255], इसलिए मैंने कुछ समय परीक्षण करने का फैसला किया।

नीचे दिए गए समय के आधार पर, और सामान्य प्रवृत्ति मैं कई विभिन्न मूल्यों और विन्यास की कोशिश कर रहा से मनाया से, struct.packसबसे तेज, जिसके बाद हो रहा है int.to_bytes, bytesऔर साथ str.encode(आश्चर्य) धीमी जा रहा है। ध्यान दें कि परिणाम प्रतिनिधित्व की तुलना में कुछ अधिक भिन्नता दिखाते हैं, int.to_bytesऔर bytesकभी-कभी परीक्षण के दौरान गति रैंकिंग को बदल दिया struct.packजाता है , लेकिन स्पष्ट रूप से सबसे तेज़ है।

विंडोज पर CPython 3.7 में परिणाम:

Testing with 63:
bytes_: 100000 loops, best of 5: 3.3 usec per loop
to_bytes: 100000 loops, best of 5: 2.72 usec per loop
struct_pack: 100000 loops, best of 5: 2.32 usec per loop
chr_encode: 50000 loops, best of 5: 3.66 usec per loop

परीक्षण मॉड्यूल (नाम int_to_byte.py):

"""Functions for converting a single int to a bytes object with that int's value."""

import random
import shlex
import struct
import timeit

def bytes_(i):
    """From Tim Pietzcker's answer:
    https://stackoverflow.com/a/21017834/8117067
    """
    return bytes([i])

def to_bytes(i):
    """From brunsgaard's answer:
    https://stackoverflow.com/a/30375198/8117067
    """
    return i.to_bytes(1, byteorder='big')

def struct_pack(i):
    """From Andy Hayden's answer:
    https://stackoverflow.com/a/26920966/8117067
    """
    return struct.pack('B', i)

# Originally, jfs's answer was considered for testing,
# but the result is not identical to the other methods
# https://stackoverflow.com/a/31761722/8117067

def chr_encode(i):
    """Another method, from Quuxplusone's answer here:
    https://codereview.stackexchange.com/a/210789/140921

    Similar to g10guang's answer:
    https://stackoverflow.com/a/51558790/8117067
    """
    return chr(i).encode('latin1')

converters = [bytes_, to_bytes, struct_pack, chr_encode]

def one_byte_equality_test():
    """Test that results are identical for ints in the range [0, 255]."""
    for i in range(256):
        results = [c(i) for c in converters]
        # Test that all results are equal
        start = results[0]
        if any(start != b for b in results):
            raise ValueError(results)

def timing_tests(value=None):
    """Test each of the functions with a random int."""
    if value is None:
        # random.randint takes more time than int to byte conversion
        # so it can't be a part of the timeit call
        value = random.randint(0, 255)
    print(f'Testing with {value}:')
    for c in converters:
        print(f'{c.__name__}: ', end='')
        # Uses technique borrowed from https://stackoverflow.com/q/19062202/8117067
        timeit.main(args=shlex.split(
            f"-s 'from int_to_byte import {c.__name__}; value = {value}' " +
            f"'{c.__name__}(value)'"
        ))

1
@ABB जैसा कि मेरे पहले वाक्य में बताया गया है, मैं इसे केवल एक ही इंट के लिए माप रहा हूँ [0, 255]। मुझे लगता है कि "गलत संकेतक" से आपको लगता है कि मेरे माप सामान्य नहीं थे कि ज्यादातर स्थितियों को फिट किया जा सके? या मेरी माप पद्धति खराब थी? यदि उत्तरार्द्ध, मुझे यह सुनने में दिलचस्पी होगी कि आपको क्या कहना है, लेकिन अगर पूर्व, मैंने कभी नहीं दावा किया कि मेरे माप सभी उपयोग के मामलों में सामान्य थे। मेरी (शायद आला) स्थिति के लिए, मैं केवल रेंज में ints के साथ काम कर रहा हूं [0, 255], और यही वह श्रोता है जिसे मैं इस उत्तर के साथ संबोधित करना चाहता हूं। क्या मेरा जवाब अस्पष्ट था? मैं इसे स्पष्टता के लिए संपादित कर सकता हूं ...
ग्राहम

1
सीमा के लिए एक पूर्वनिर्मित एन्कोडिंग को केवल अनुक्रमित करने की तकनीक के बारे में क्या? पूर्वसंक्रमण समय के अधीन नहीं होगा, केवल अनुक्रमण होगा।
एक्यूमेनस

@ABB यह एक अच्छा विचार है। ऐसा लगता है कि यह कुछ और की तुलना में तेज हो जाएगा। मैं कुछ समय दूंगा और इसे इस उत्तर में जोड़ूंगा जब मेरे पास कुछ समय होगा।
ग्राहम

3
यदि आप वास्तव में बाइट्स-से-iterable चीज को समय देना चाहते हैं, तो आपको bytes((i,))इसके बजाय उपयोग करना चाहिए bytes([i])क्योंकि सूची अधिक जटिल है, अधिक मेमोरी का उपयोग करें और प्रारंभिक करने के लिए लंबा समय लें। इस मामले में, कुछ भी नहीं के लिए।
बछसौ

4

हालांकि ब्रुन्सगार्ड द्वारा पूर्व उत्तर एक कुशल एन्कोडिंग है, यह केवल अहस्ताक्षरित पूर्णांक के लिए काम करता है। यह हस्ताक्षरित और अहस्ताक्षरित पूर्णांक दोनों के लिए काम करने के लिए इसे बनाता है।

def int_to_bytes(i: int, *, signed: bool = False) -> bytes:
    length = ((i + ((i * signed) < 0)).bit_length() + 7 + signed) // 8
    return i.to_bytes(length, byteorder='big', signed=signed)

def bytes_to_int(b: bytes, *, signed: bool = False) -> int:
    return int.from_bytes(b, byteorder='big', signed=signed)

# Test unsigned:
for i in range(1025):
    assert i == bytes_to_int(int_to_bytes(i))

# Test signed:
for i in range(-1024, 1025):
    assert i == bytes_to_int(int_to_bytes(i, signed=True), signed=True)

एनकोडर के लिए, (i + ((i * signed) < 0)).bit_length()इसका उपयोग सिर्फ i.bit_length()इसलिए किया जाता है क्योंकि उत्तरार्द्ध -128, -32768, आदि के एक अक्षम एन्कोडिंग की ओर जाता है।


क्रेडिट: मामूली अक्षमता को ठीक करने के लिए गर्भाशय ग्रीवा।


int_to_bytes(-128, signed=True) == (-128).to_bytes(1, byteorder="big", signed=True)हैFalse
CervEd

आप लंबाई 2 का उपयोग नहीं कर रहे हैं, आप हस्ताक्षर किए गए पूर्णांक की थोड़ी लंबाई की गणना कर रहे हैं, अगर यह एक हस्ताक्षरित पूर्णांक है, तो 7 और फिर 1 जोड़ रहा है। अंत में आप इसे बाइट्स में लंबाई में परिवर्तित करते हैं। इसके लिए अप्रत्याशित परिणाम मिलते हैं -128, -32768आदि
CervEd


यह आप इसे कैसे ठीक करते हैं(i+(signed*i<0)).bit_length()
CervEd

3

व्यवहार इस तथ्य से आता है कि संस्करण 3 से पहले पायथन bytesमें सिर्फ एक उपनाम था str। Python3.x bytesमें एक अपरिवर्तनीय संस्करण है bytearray- पूरी तरह से नए प्रकार का, पीछे की ओर संगत नहीं।


3

से डॉक्स बाइट्स :

तदनुसार, कंस्ट्रक्टर तर्कों की व्याख्या बायटियर () के रूप में की जाती है।

फिर, bytearray डॉक्स से :

वैकल्पिक स्रोत पैरामीटर का उपयोग कुछ भिन्न तरीकों से सरणी को आरंभ करने के लिए किया जा सकता है:

  • यदि यह एक पूर्णांक है, तो सरणी में वह आकार होगा और नल बाइट्स के साथ आरंभीकृत किया जाएगा।

ध्यान दें, जो 2.x (जहां x> = 6) व्यवहार से भिन्न है, जहां bytesबस है str:

>>> bytes is str
True

पीईपी 3112 :

२.६ str विभिन्न तरीकों से ३.० बाइट्स प्रकार से भिन्न होता है; सबसे विशेष रूप से, कंस्ट्रक्टर पूरी तरह से अलग है।


0

कुछ उत्तर बड़ी संख्या के साथ काम नहीं करते हैं।

पूर्णांक को हेक्स प्रतिनिधित्व में बदलें, फिर इसे बाइट में बदलें:

def int_to_bytes(number):
    hrepr = hex(number).replace('0x', '')
    if len(hrepr) % 2 == 1:
        hrepr = '0' + hrepr
    return bytes.fromhex(hrepr)

परिणाम:

>>> int_to_bytes(2**256 - 1)
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

1
"अन्य सभी विधियां बड़ी संख्या में काम नहीं करती हैं।" यह सच नहीं है, int.to_bytesकिसी भी पूर्णांक के साथ काम करता है।
जुआनपा। श्रीविलगागा

@ juanpa.arrivillaga हाँ, मेरा बुरा। मैंने अपना उत्तर संपादित कर दिया है।
मैक्स मालेश

-1

यदि प्रश्न यह है कि पूर्णांक को स्वयं (इसके स्ट्रिंग समतुल्य नहीं) बाइट्स में कैसे परिवर्तित किया जाए, तो मुझे लगता है कि इसका मजबूत उत्तर है:

>>> i = 5
>>> i.to_bytes(2, 'big')
b'\x00\x05'
>>> int.from_bytes(i.to_bytes(2, 'big'), byteorder='big')
5

इन तरीकों की अधिक जानकारी यहाँ:

  1. https://docs.python.org/3.8/library/stdtypes.html#int.to_bytes
  2. https://docs.python.org/3.8/library/stdtypes.html#int.from_bytes

1
5 साल पहले पोस्ट किए गए ब्रून्सगार्ड के उत्तर और वर्तमान में सबसे अधिक मतदान वाले उत्तर से यह कैसे भिन्न है?
आर्थर टाका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.