code: def get_attributes(self, sids, flds, **overrides):
          
          # Unfortunately must be inefficient with request
          flds = _force_array(flds)
          sids = _force_array(sids)
          cached = self._cache_get_attribute(sids, flds, **overrides)
          if not cached:  # build get
              df = self.dm.get_attributes(sids, flds, **overrides)
              [self._cache_update_attribute(sid, df.ix[sid:sid], **overrides) for sid in sids]
              return df
          else:
              # Retrieve all missing and merge with existing cache
              for sid in sids:
                  missed = flds if sid not in cached else set(flds) - set(cached[sid].columns)
                  if missed:
                      df = self.dm.get_attributes(sid, missed, **overrides)
                      self._cache_update_attribute(sid, df, **overrides)
  
              # now just retrieve from cache
              data = self._cache_get_attribute(sids, flds, **overrides)
              # reindex and grab columns to sort
              frame = pd.concat(data.values())
              return frame
docs: Check cache first, then defer to data manager
          :param sids: security identifiers
          :param flds: fields to retrieve
          :param overrides: key-value pairs to pass to the mgr get_attributes method
          :return: DataFrame with flds as columns and sids as the row indices