def Table(self, name, create=True, restricted=False, columns=None, keys=None,
            timeout=None):
    """Returns the Table object for existing table name.

    Args:
      name: The table name.
      create: If True creates the table if it does not exist.
      restricted: Return a restricted table object.
      columns: The number of columns in each row.
      keys: The number of columns, left to right, that are primary keys. 0 for
        all columns.
      timeout: The number of seconds after last modification when the table
        becomes invalid. 0 for no timeout. If None then the default cache
        timeout is assumed.

    Raises:
      CacheTableNameInvalid: name is not a valid table name.
      CacheTableNotFound: If the table does not exist.

    Returns:
      A Table object for name.
    """
    if name in self._restricted:
      raise exceptions.CacheTableRestricted(
          '[{}] cache table [{}] is restricted.'.format(self.name, name))
    table = self._tables.get(name, None)
    if table:
      if not table.deleted:
        if columns is not None and columns != table.columns:
          raise exceptions.CacheTableColumnsInvalid(
              '[{}] cache table [{}] columns [{}] does not match existing {}.'
              .format(self.name, name, columns, table.columns))
        if keys is not None and keys != table.keys:
          raise exceptions.CacheTableKeysInvalid(
              '[{}] cache table [{}] keys [{}] does not match existing {}.'
              .format(self.name, name, keys, table.keys))
        return table
      if not create:
        raise exceptions.CacheTableNotFound(
            '[{}] cache table [{}] not found.'.format(self.name, name))
    if self._metadata:
      rows = self._metadata.Select(Metadata.Row(name=name))
      row = rows[0] if rows else None
      if row:
        metadata = Metadata(row)
        return self._table_class(self,
                                 name=metadata.name,
                                 columns=metadata.columns,
                                 keys=metadata.keys,
                                 timeout=metadata.timeout,
                                 modified=metadata.modified,
                                 restricted=metadata.restricted)
    if not create:
      raise exceptions.CacheTableNotFound(
          '[{}] cache table [{}] not found.'.format(self.name, name))
    return self._CreateTable(name, restricted, columns, keys, timeout)
  def _CreateTable(self, name, restricted, columns, keys, timeout):
    """Creates and returns a table object for name.

    NOTE: This code is conditioned on self._metadata. If self._metadata is None
    then we are initializing/updating the metadata table. The table name is
    relaxed, in particular '_' is allowed in the table name. This avoids user
    table name conflicts. Finally, self._metadata is set and the metadata
    table row is updated to reflect any changes in the default timeout.

    Args:
      name: The table name.
      restricted: Return a restricted table object.
      columns: The number of columns in each row.
      keys: The number of columns, left to right, that are primary keys. 0 for
        all columns.
      timeout: The number of seconds after last modification when the table
        becomes invalid. 0 for no timeout.

    Raises:
      CacheTableNameInvalid: If name is invalid.

    Returns:
      A table object for name.
    """
    if columns is None:
      columns = 1
    if columns < 1:
      raise exceptions.CacheTableColumnsInvalid(
          '[{}] table [{}] column count [{}] must be >= 1.'.format(
              self.name, name, columns))
    if keys is None:
      keys = columns
    if keys < 1 or keys > columns:
      raise exceptions.CacheTableKeysInvalid(
          '[{}] table [{}] primary key count [{}] must be >= 1 and <= {}.'
          .format(self.name, name, keys, columns))
    if timeout is None:
      timeout = self.timeout
    self._ImplementationCreateTable(name, columns, keys)
    table = self._table_class(self,
                              name=name,
                              columns=columns,
                              keys=keys,
                              timeout=timeout,
                              modified=0,
                              restricted=restricted)
    if self._metadata:
      version = None
    else:
      # Initializing the metadata table -- get its Table object.
      self._metadata = table
      table.Validate()
      rows = table.Select(Metadata.Row(name=name))
      row = rows[0] if rows else None
      if row:
        metadata = Metadata(row)
        if self.version is None:
          self.version = metadata.version or ''
        elif self.version != metadata.version:
          raise exceptions.CacheVersionMismatch(
              '[{}] cache version [{}] does not match [{}].'.format(
                  self.name, metadata.version, self.version),
              metadata.version, self.version)
        if self.timeout is None:
          self.timeout = metadata.timeout
      table.modified = 0
      version = self.version
    self._metadata.AddRows([Metadata.Row(
        name=table.name,
        columns=table.columns,
        keys=table.keys,
        timeout=table.timeout,
        modified=table.modified,
        restricted=table.restricted,
        version=version)])
    return table