docs: def _expand_list(names):
    """ Do a wildchar name expansion of object names in a list and return expanded list.
  
      The objects are expected to exist as this is used for copy sources or delete targets.
      Currently we support wildchars in the key name only.
    """
  
    if names is None:
      names = []
    elif isinstance(names, basestring):
      names = [names]
  
    results = []  # The expanded list.
    objects = {}  # Cached contents of buckets; used for matching.
    for name in names:
      bucket, key = google.datalab.storage._bucket.parse_name(name)
      results_len = len(results)  # If we fail to add any we add name and let caller deal with it.
      if bucket:
        if not key:
          # Just a bucket; add it.
          results.append('gs://%s' % bucket)
        elif google.datalab.storage.Object(bucket, key).exists():
          results.append('gs://%s/%s' % (bucket, key))
        else:
          # Expand possible key values.
          if bucket not in objects and key[:1] == '*':
            # We need the full list; cache a copy for efficiency.
            objects[bucket] = [obj.metadata.name
                               for obj in list(google.datalab.storage.Bucket(bucket).objects())]
          # If we have a cached copy use it
          if bucket in objects:
            candidates = objects[bucket]
          # else we have no cached copy but can use prefix matching which is more efficient than
          # getting the full contents.
          else:
            # Get the non-wildchar prefix.
            match = re.search('\?|\*|\[', key)
            prefix = key
            if match:
              prefix = key[0:match.start()]
  
            candidates = [obj.metadata.name
                          for obj in google.datalab.storage.Bucket(bucket).objects(prefix=prefix)]
  
          for obj in candidates:
            if fnmatch.fnmatch(obj, key):
              results.append('gs://%s/%s' % (bucket, obj))
  
      # If we added no matches, add the original name and let caller deal with it.
      if len(results) == results_len:
        results.append(name)
  
    return results