title: Write string of escaped byte characters, ie '\x00\x20\...', as if they were bytes
body: <p>I am playing around with .wav file generation and have functions to convert base 10 integer into hexadecimal. I need to write these hex numbers as if they were bytes, not simply encoding them to be written as bytes. I can hard code using escape sequences but I need to use strings provided by my functions.</p>
  
  <p>My temporary work around makes use of eval as follows.</p>
  
  <pre><code>eval("b'" + endian(bytestring(tohex(16, 32))) + "'")
  </code></pre>
  
  <p>What is a more preferred method to accomplish this task without eval?</p>
  
  <p>Here is some code to better understand the situation.</p>
  
  <pre><code>with open('song.wav', 'wb') as f:
      f.write(ChunkID)
      f.write(ChunkSize)
      f.write(Format)
      f.write(Subchunk1ID)
      f.write(Subchunk1Size)
      f.write(AudioFormat)
      f.write(NumChannels)
      f.write(SampleRate)
      f.write(ByteRate)
      f.write(BlockAlign)
      f.write(BitsPerSample)
      f.write(Subchunk2ID)
      f.write(Subchunk2Size)
      f.write(Data)
  </code></pre>
  
  <p>Using hard coded values works fine.</p>
  
  <pre><code>ChunkID = b'RIFF'               #big        1
  ChunkSize = b'\x1a\xea\xc4\x00'     #little     2
  Format = b'WAVE'                #big        3
  Subchunk1ID = b'fmt '               #big        4
  Subchunk1Size = b'\x10\x00\x00\x00'         #little     5
  AudioFormat = b'\x01\x00'           #little     6
  NumChannels = b'\x02\x00'           #little     7
  SampleRate = b'\x22\x56\x00\x00'        #little     8
  ByteRate = b'\x88\x58\x01\x00'          #little     9
  BlockAlign = b'\x04\x00'            #little     10
  BitsPerSample = b'\x10\x00'         #little     11
  Subchunk2ID = b'data'               #big        12
  Subchunk2Size = b'\x10\xb1\x02\x00'     #little     13
  Data = b''                  #little     14
  </code></pre>
  
  <p>I need more flexibility and need similar results using functions.</p>
  
  <pre><code>def tohex(val, nbits):
      a = hex((val + (1 &lt;&lt; nbits)) % (1 &lt;&lt; nbits))
      pad = nbits/4 - (len(a) - 2)
      for i in range(0, pad):
          a = a[:2] + '0' + a[2:]
      return a
  def bytestring(hexstring):
      hexstring = hexstring[2:]
      bstring = ''
      for i in range(0, len(hexstring)/2):
          bstring += '\\x'
          bstring += hexstring[2*i: 2*i+2]
      return bstring
  def endian(bstring):
      return '\\'+'\\'.join(reversed(bstring.split('\\'))).rstrip('\\')
  </code></pre>
  
  <p>This is how I call the functions</p>
  
  <pre><code>sample_rate = 44100
  channels = 2
  sample_bits = 16
  sample_count = 176400
  
  ChunkID = b'RIFF'
  Format = b'WAVE'
  Subchunk1ID = b'fmt '
  Subchunk1Size = eval("b'" + endian(bytestring(tohex(16, 32))) + "'")    #n bit samples : tohex(n,m)
  AudioFormat = eval("b'" + endian(bytestring(tohex(1, 16))) + "'")       #uncompressed when n=1
  NumChannels = eval("b'" + endian(bytestring(tohex(channels, 16))) + "'")        #n channels
  SampleRate = eval("b'" + endian(bytestring(tohex(sample_rate, 32))) + "'")
  BitsPerSample = eval("b'" + endian(bytestring(tohex(sample_bits, 16))) + "'")
  ByteRate = eval("b'" +  endian(bytestring(tohex(sample_rate*channels*sample_bits/8, 32))) + "'")
  BlockAlign = eval("b'" + endian(bytestring(tohex(channels*sample_bits/8, 16))) + "'")
  Subchunk2ID = b'data'
  Subchunk2Size = eval("b'" + endian(bytestring(tohex(sample_count*channels*sample_bits/8, 32))) + "'")
  ChunkSize = eval("b'" + endian(bytestring(tohex(36 + sample_count*channels*sample_bits/8, 32))) + "'")
  Data = b''
  
  for i in range(0, 176400): #Just test samples
      if i % 32 &lt; 16:
          Data += b'\x10\xe7\x10\xe7'
      else:
          Data += b'\xf0\xa8\xf0\xa8'
  </code></pre>
  
  <p>Update: I added a new function to handle previous formatting and return a form I can write directly to file. The solution I marked makes use of bytes but in python 2.7 I had to use bytearray.</p>
  
  <pre><code>def barray(bstring):
      hexmap = {'0':0, '1':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7,'8':8, '9':9, 'a':10, 'b':11, 'c':12, 'd':13, 'e':14, 'f':15}
      bstring = bstring.lstrip('\\x')
      bstring = bstring.split('\\x')
      bstring = map(lambda x: 16*hexmap[x[0]]+hexmap[x[1]], bstring)
      return bytearray(bstring)
  </code></pre>
  
  <p>Now after I call the functions the data is ready to write to file without using eval().</p>
  
  <pre><code>variable = barray(endian(bytestring(tohex(n, m))))
  </code></pre>