title: Flatten nested dictionaries with tuple keys
body: <p>How to generalize this <a href="https://stackoverflow.com/questions/6027558/flatten-nested-dictionaries-compressing-keys">question</a> to the case keys that may be tuples? </p>
  
  <p>As a benefit even in the case of all string keys, if these are accumulated to a tuple, there's no need for ad-hoc separators (though JSON export is another matter):</p>
  
  <p>one approach is to base it on this <a href="https://stackoverflow.com/a/19647596/1472770">answer</a>. I tried 2 versions:</p>
  
  <pre><code>def flatten_keys(d,handler,prefix=[]):
      return {handler(prefix,k) if prefix else k : v
          for kk, vv in d.items()
          for k, v in flatten_keys(vv, handler, kk).items()
          } if isinstance(d, dict) else { prefix : d }
  </code></pre>
  
  <p>where the tuple handlers are:</p>
  
  <pre><code>def tuple_handler_1(prefix,k):
      return tuple([prefix]+[k])
  
  def tuple_handler_2(prefix,k):
      return tuple(flatten_container((prefix,k)))
  </code></pre>
  
  <p>Using the utility generator:</p>
  
  <pre><code>def flatten_container(container):
      for i in container:
          if isinstance(i, (list,tuple)):
              for j in flatten_container(i):
                  yield j
          else:
              yield i
  </code></pre>
  
  <p>Consider one of the test dict's but using a tuple key <code>('hgf',1)</code>:</p>
  
  <pre><code>data =  {'abc':123, ('hgf',1):{'gh':432, 'yu':433}, 'gfd':902, 'xzxzxz':{"432":{'0b0b0b':231}, "43234":1321}}
  </code></pre>
  
  <p>Neither works as intended: </p>
  
  <pre><code>flatten_keys(data,tuple_handler_1)
  </code></pre>
  
  <blockquote>
    <p>{'abc': 123,  (('hgf', 1), 'gh'): 432,  (('hgf', 1), 'yu'): 433, 
    'gfd': 902,  ('xzxzxz', ('432', '0b0b0b')): 231,  ('xzxzxz', '43234'):
    1321}</p>
  </blockquote>
  
  <p><code>('xzxzxz', ('432', '0b0b0b'))</code>. is not flattened</p>
  
  <p>And the 2nd flattens the input tuple key</p>
  
  <pre><code>flatten_keys(data,tuple_handler_2)
  </code></pre>
  
  <blockquote>
    <p>{'abc': 123,  ('hgf', 1, 'gh'): 432,  ('hgf', 1, 'yu'): 433,  'gfd':
    902,  ('xzxzxz', '432', '0b0b0b'): 231,  ('xzxzxz', '43234'): 1321}</p>
  </blockquote>
  
  <p>Is there an obvious modification of the flatten method that will correctly join strings and other hashables?</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>As per comments below, a problem handling key-clash with this method is inherent the base case of strings keys, eg <code>{'a_b':{'c':1}, 'a':{'b_c':2}}</code>. </p>
  
  <p>Thus each key path should be a be tuple even in for <code>len</code> 1 key paths to avoid key clash eg  <code>{((1,2),): 3, (1,2):4}}</code>. </p>