title: How to convert generator or iterator to list recursively
body: <p>I want to convert generator or iterator to list recursively.<BR>
  I wrote a code in below, but it looks naive and ugly, and may be dropped case in doctest.</p>
  
  <p>Q1. Help me good version. <BR>
  Q2. How to specify object is immutable or not? <BR></p>
  
  <pre><code>import itertools
  
  def isiterable(datum):
      return hasattr(datum, '__iter__')
  
  def issubscriptable(datum):
      return hasattr(datum, "__getitem__")
  
  def eagerlize(obj):
      """ Convert generator or iterator to list recursively.
      return a eagalized object of given obj.
      This works but, whether it return a new object, break given one.
  
      test 1.0 iterator
  
      &gt;&gt;&gt; q = itertools.permutations('AB',  2)
      &gt;&gt;&gt; eagerlize(q)
      [('A', 'B'), ('B', 'A')]
      &gt;&gt;&gt;
  
      test 2.0 generator in list
  
      &gt;&gt;&gt; q = [(2**x for x in range(3))]
      &gt;&gt;&gt; eagerlize(q)
      [[1, 2, 4]]
      &gt;&gt;&gt;
  
      test 2.1 generator in tuple
  
      &gt;&gt;&gt; q = ((2**x for x in range(3)),)
      &gt;&gt;&gt; eagerlize(q)
      ([1, 2, 4],)
      &gt;&gt;&gt;
  
      test 2.2 generator in tuple in generator
  
      &gt;&gt;&gt; q = (((x, (y for y in range(x, x+1))) for x in range(3)),)
      &gt;&gt;&gt; eagerlize(q)
      ([(0, [0]), (1, [1]), (2, [2])],)
      &gt;&gt;&gt;
  
      test 3.0 complex test
  
      &gt;&gt;&gt; def test(r):
      ...     for x in range(3):
      ...         r.update({'k%s'%x:x})
      ...         yield (n for n in range(1))
      &gt;&gt;&gt;
      &gt;&gt;&gt; def creator():
      ...     r = {}
      ...     t = test(r)
      ...     return r, t
      &gt;&gt;&gt;
      &gt;&gt;&gt; a, b = creator()
      &gt;&gt;&gt; q = {'b' : a, 'a' : b}
      &gt;&gt;&gt; eagerlize(q)
      {'a': [[0], [0], [0]], 'b': {'k2': 2, 'k1': 1, 'k0': 0}}
      &gt;&gt;&gt;
  
      test 3.1 complex test (other dict order)
  
      &gt;&gt;&gt; a, b = creator()
      &gt;&gt;&gt; q = {'b' : b, 'a' : a}
      &gt;&gt;&gt; eagerlize(q)
      {'a': {'k2': 2, 'k1': 1, 'k0': 0}, 'b': [[0], [0], [0]]}
      &gt;&gt;&gt;
  
      test 4.0 complex test with tuple
  
      &gt;&gt;&gt; a, b = creator()
      &gt;&gt;&gt; q = {'b' : (b, 10), 'a' : (a, 10)}
      &gt;&gt;&gt; eagerlize(q)
      {'a': ({'k2': 2, 'k1': 1, 'k0': 0}, 10), 'b': ([[0], [0], [0]], 10)}
      &gt;&gt;&gt;
  
      test 4.1 complex test with tuple (other dict order)
  
      &gt;&gt;&gt; a, b = creator()
      &gt;&gt;&gt; q = {'b' : (b, 10), 'a' : (a, 10)}
      &gt;&gt;&gt; eagerlize(q)
      {'a': ({'k2': 2, 'k1': 1, 'k0': 0}, 10), 'b': ([[0], [0], [0]], 10)}
      &gt;&gt;&gt;
  
      """
      def loop(obj):
          if isiterable(obj):
              for k, v in obj.iteritems() if isinstance(obj, dict) \
                           else enumerate(obj):
                  if isinstance(v, tuple):
                      # immutable and iterable object must be recreate, 
                      # but realy only tuple?
                      obj[k] = tuple(eagerlize(list(obj[k])))
                  elif issubscriptable(v):
                      loop(v)
                  elif isiterable(v):
                      obj[k] = list(v)
                      loop(obj[k])
  
      b = [obj]
      loop(b)
      return b[0]
  
  def _test():
      import doctest
      doctest.testmod()
  
  if __name__=="__main__":
      _test()
  </code></pre>