-1

What is the difference between writing a null byte with:

print("\x00")

And writing one with:

print(struct.pack("B", 0))

I've taken the liberty of timing both of their execution times with the following:

def struct_exec_time():
    start_time = time.time()
    import struct
    print(struct.pack("B",0))
    return time.time() - start_time

def simple_print_exec():
    start_time = time.time()
    print("\x00")
    return time.time() - start_time

When running them both:

>>> for _ in range(1):
...     print("Struct execution time: {}".format(struct_exec_time()))
...     print("Simple print execution time: {}".format(simple_print_exec()))
... 

Struct execution time: 2.38418579102e-05

Simple print execution time: 3.09944152832e-06
>>> 

It seems that struct is faster then the print function for the first execution, because if you run them more then once:

>>> for _ in range(5):
...     print("Struct execution time: {}".format(struct_exec_time()))
...     print("Simple print execution time: {}".format(simple_print_exec()))
... 

Struct execution time: 2.71797180176e-05

Simple print execution time: 5.00679016113e-06

Struct execution time: 9.05990600586e-06

Simple print execution time: 4.05311584473e-06

Struct execution time: 7.15255737305e-06

Simple print execution time: 5.00679016113e-06

Struct execution time: 7.15255737305e-06

Simple print execution time: 4.05311584473e-06

Struct execution time: 6.91413879395e-06

Simple print execution time: 4.76837158203e-06

So, what is the difference between the two, and why is struct only faster then print once?


Edit:

With the import struct call taken out of the timer:

def struct_exec_time():
    import struct
    start_time = time.time()
    print(struct.pack("B",0))
    return time.time() - start_time

for _ in range(5):
    print("Struct exec: {}".format(struct_exec_time()))
    print("Print exec: {}".format(simple_print_exec()))


Struct exec: 3.40938568115e-05

Print exec: 2.86102294922e-06

Struct exec: 2.86102294922e-06

Print exec: 3.09944152832e-06

Struct exec: 2.86102294922e-06

Print exec: 3.09944152832e-06

Struct exec: 3.81469726562e-06

Print exec: 3.09944152832e-06

Struct exec: 2.86102294922e-06

Print exec: 2.14576721191e-06
CertifcateJunky
  • 161
  • 1
  • 11

2 Answers2

2

If you are using Python 2.7 the two values are equal and of the same type: str (= Python 3 bytes).

Here is a python 2/3 test:

import struct

b1 = struct.pack('B', 0)
b2 = b'\x00'

assert b1 == b2
assert type(b1) == type(b2)

In every day programming I would prefer using a bytes string instead of using struct.

Quoting the documentation:

This module performs conversions between Python values and C structs represented as Python bytes objects.

Edit

Note about performance: b’\x00’ is a literal. Compared to a function call, the evaluation of a literal is always faster.

Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
0

They are not the same.

print("\x00")

This prints the unicode codepoint 0; The unicode will be decoded to your terminal's encoding (utf-8 by default) and the corresponding bytes will be sent to your process' stdout

print(struct.pack("B", 0))

This prints the null byte representation. Since the result of struct.pack() is a bytestring, python won't try to encode it and print() will convert it to a representation:

>>> print('\x00')

>>> import struct
>>> print(struct.pack("B", 0))
b'\x00'
nosklo
  • 217,122
  • 57
  • 293
  • 297
  • Do you know where you read that `print("\x00")` prints unicode codepoint 0? And can you link it here? – CertifcateJunky Jul 05 '18 at 20:07
  • @CertifcateJunky I just realized you're using python 2 - in python 3 all strings are unicode codepoint collections, and to have bytestrings you use the `b'\x00'` prefix. – nosklo Jul 05 '18 at 20:10