docs: def _update_hasher(hasher, data):
      """
      This is the clear winner over the generate version.
      Used by hash_data
  
      Ignore:
          import utool
          rng = np.random.RandomState(0)
          # str1 = rng.rand(0).dumps()
          str1 = b'SEP'
          str2 = rng.rand(10000).dumps()
          for timer in utool.Timerit(100, label='twocall'):
              hasher = hashlib.sha256()
              with timer:
                  hasher.update(str1)
                  hasher.update(str2)
          a = hasher.hexdigest()
          for timer in utool.Timerit(100, label='concat'):
              hasher = hashlib.sha256()
              with timer:
                  hasher.update(str1 + str2)
          b = hasher.hexdigest()
          assert a == b
          # CONCLUSION: Faster to concat in case of prefixes and seps
  
          nested_data = {'1': [rng.rand(100), '2', '3'],
                         '2': ['1', '2', '3', '4', '5'],
                         '3': [('1', '2'), ('3', '4'), ('5', '6')]}
          data = list(nested_data.values())
  
  
          for timer in utool.Timerit(1000, label='cat-generate'):
              hasher = hashlib.sha256()
              with timer:
                  hasher.update(b''.join(_bytes_generator(data)))
  
          for timer in utool.Timerit(1000, label='inc-generate'):
              hasher = hashlib.sha256()
              with timer:
                  for b in _bytes_generator(data):
                      hasher.update(b)
  
          for timer in utool.Timerit(1000, label='inc-generate'):
              hasher = hashlib.sha256()
              with timer:
                  for b in _bytes_generator(data):
                      hasher.update(b)
  
          for timer in utool.Timerit(1000, label='chunk-inc-generate'):
              hasher = hashlib.sha256()
              import ubelt as ub
              with timer:
                  for chunk in ub.chunks(_bytes_generator(data), 5):
                      hasher.update(b''.join(chunk))
  
          for timer in utool.Timerit(1000, label='inc-update'):
              hasher = hashlib.sha256()
              with timer:
                  _update_hasher(hasher, data)
  
          data = ut.lorium_ipsum()
          hash_data(data)
          ut.hashstr27(data)
          %timeit hash_data(data)
          %timeit ut.hashstr27(repr(data))
  
          for timer in utool.Timerit(100, label='twocall'):
              hasher = hashlib.sha256()
              with timer:
                  hash_data(data)
  
          hasher = hashlib.sha256()
          hasher.update(memoryview(np.array([1])))
          print(hasher.hexdigest())
  
          hasher = hashlib.sha256()
          hasher.update(np.array(['1'], dtype=object))
          print(hasher.hexdigest())
  
      """
      if isinstance(data, (tuple, list, zip)):
          needs_iteration = True
      elif (util_type.HAVE_NUMPY and isinstance(data, np.ndarray) and
            data.dtype.kind == 'O'):
          # ndarrays of objects cannot be hashed directly.
          needs_iteration = True
      else:
          needs_iteration = False
  
      if needs_iteration:
          # try to nest quickly without recursive calls
          SEP = b'SEP'
          iter_prefix = b'ITER'
          # if isinstance(data, tuple):
          #     iter_prefix = b'TUP'
          # else:
          #     iter_prefix = b'LIST'
          iter_ = iter(data)
          hasher.update(iter_prefix)
          try:
              for item in iter_:
                  prefix, hashable = _covert_to_hashable(data)
                  binary_data = SEP + prefix + hashable
                  # b''.join([SEP, prefix, hashable])
                  hasher.update(binary_data)
          except TypeError:
              # need to use recursive calls
              # Update based on current item
              _update_hasher(hasher, item)
              for item in iter_:
                  # Ensure the items have a spacer between them
                  hasher.update(SEP)
                  _update_hasher(hasher, item)
      else:
          prefix, hashable = _covert_to_hashable(data)
          binary_data = prefix + hashable
          # b''.join([prefix, hashable])
          hasher.update(binary_data)