Opens the named object.

    DeletionPool will only open the object if it's not in the pool already.
    Otherwise it will just return the cached version. Objects are cached
    based on their urn and mode. I.e. same object opened with mode="r" and
    mode="rw" will be actually opened two times and cached separately.

    DeletionPool's Open() also doesn't follow symlinks.

    Args:
      urn: The urn to open.
      aff4_type: If this parameter is set, we raise an IOError if the object is
        not an instance of this type.
      mode: The mode to open the file with.

    Returns:
      An AFF4Object instance.

    Raises:
      IOError: If the object is not of the required type.

def Open(self, urn, aff4_type=None, mode="r"):
    """Opens the named object.

    DeletionPool will only open the object if it's not in the pool already.
    Otherwise it will just return the cached version. Objects are cached
    based on their urn and mode. I.e. same object opened with mode="r" and
    mode="rw" will be actually opened two times and cached separately.

    DeletionPool's Open() also doesn't follow symlinks.

    Args:
      urn: The urn to open.
      aff4_type: If this parameter is set, we raise an IOError if the object is
        not an instance of this type.
      mode: The mode to open the file with.

    Returns:
      An AFF4Object instance.

    Raises:
      IOError: If the object is not of the required type.
    """
    key = self._ObjectKey(urn, mode)

    try:
      obj = self._objects_cache[key]
    except KeyError:
      obj = FACTORY.Open(
          urn, mode=mode, follow_symlinks=False, token=self._token)
      self._objects_cache[key] = obj

    if aff4_type is not None and not isinstance(obj, aff4_type):
      raise InstantiationError(
          "Object %s is of type %s, but required_type is %s" %
          (urn, obj.__class__.__name__, aff4_type.__name__))

    return obj