diff --git a/bob/io/base/__init__.py b/bob/io/base/__init__.py
index d84289b2a75e4f931e5d45ace768a23299d83605..ca1d2581da304c66a55dc0306521346539e21da4 100644
--- a/bob/io/base/__init__.py
+++ b/bob/io/base/__init__.py
@@ -6,7 +6,7 @@ import bob.core
 import bob.extension
 bob.extension.load_bob_library('bob.io.base', __file__)
 
-from ._library import File as File_C, HDF5File as HDF5File_C, extensions
+from ._library import File as _File_C, HDF5File as _HDF5File_C, extensions
 from . import version
 from .version import module as __version__
 from .version import api as __api_version__
@@ -14,8 +14,8 @@ from .version import api as __api_version__
 import os
 
 
-class File(File_C):
-  __doc__ = File_C.__doc__
+class File(_File_C):
+  __doc__ = _File_C.__doc__
 
   def __enter__(self):
     return self
@@ -24,24 +24,51 @@ class File(File_C):
     self.close()
 
 
-class HDF5File(HDF5File_C):
-  __doc__ = HDF5File_C.__doc__
+class HDF5File(_HDF5File_C):
+  __doc__ = _HDF5File_C.__doc__
 
   def __enter__(self):
     return self
 
   def __exit__(self, type, value, traceback):
-    self.close()
+    return self.close()
 
   def __contains__(self, x):
-    """Since .has_key() is deprecated, implement the ``in`` operator to avoid
-    PEP8 W601.
-    """
+    __doc__ = self.has_key.__doc__
     return self.has_key(x)
 
   def __iter__(self):
+    __doc__ = self.keys.__doc__
     return iter(self.keys())
 
+  def __getitem__(self, name):
+    __doc__ = self.get.__doc__
+    return self.get(name)
+
+  def __setitem__(self, name, value):
+    __doc__ = self.set.__doc__
+    return self.set(name, value)
+
+  def values(self):
+    '''Yields the datasets contained in the current directory.
+
+    Yields
+    -------
+    object
+        The datasets that are being read.
+    '''
+    return (self[key] for key in self)
+
+  def items(self):
+    '''Yields the keys and the datasets contained in the current directory.
+
+    Yields
+    -------
+    tuple
+        The key and the datasets that are being read in a tuple.
+    '''
+    return ((key, self[key]) for key in self)
+
 
 def _is_string(s):
   """Returns ``True`` if the given object is a string
diff --git a/bob/io/base/test_hdf5.py b/bob/io/base/test_hdf5.py
index fcc5811ce60903393cfc6a8695e6ebc682e8db88..64d5a6bb353d09a95c4de7b41a24e11841ac9a0e 100644
--- a/bob/io/base/test_hdf5.py
+++ b/bob/io/base/test_hdf5.py
@@ -477,10 +477,8 @@ def test_copy_constructor():
 
     assert shallow.has_group("/Test")
     assert shallow.has_key("/Test/Data")
-    assert "/Test/Data" in shallow
     assert hdf5.filename == shallow.filename
     assert hdf5.keys() == shallow.keys()
-    assert [key for key in hdf5] == shallow.keys()
     assert hdf5.cwd == shallow.cwd
 
     assert not deep.has_group("/Test")
@@ -512,3 +510,23 @@ def test_copy_constructor():
   finally:
     os.unlink(tmpname)
     os.unlink(tmpname2)
+
+
+def test_python_interfaces():
+  try:
+    tmpname = test_utils.temporary_filename()
+    with HDF5File(tmpname, 'w') as hdf5:
+      a = numpy.arange(10)
+      b = a * 2
+      hdf5['Data'] = a
+      hdf5.create_group('Group1')
+      hdf5['Group1/Data'] = b
+      assert "/Group1/Data" in hdf5
+      assert [key for key in hdf5] == hdf5.keys()
+      assert numpy.allclose(hdf5['Data'], hdf5.get('Data'))
+      assert all(numpy.allclose(c, d) for c, d in zip(hdf5.values(), (a, b)))
+      for key, value in hdf5.items():
+        assert numpy.allclose(value, hdf5[key])
+
+  finally:
+    os.unlink(tmpname)
diff --git a/doc/guide.rst b/doc/guide.rst
index 7ecdd8c09f1fd12511505506baf8e1a4a6eb3558..5533f6bc52ecc26512f83e6bdddb21fbba93496c 100644
--- a/doc/guide.rst
+++ b/doc/guide.rst
@@ -157,9 +157,9 @@ is an example:
   >>> A = numpy.array(range(4), 'int8').reshape(2,2)
   >>> f = bob.io.base.HDF5File('testfile1.hdf5', 'a')
   >>> f.set('my_array', A)
-  >>> del f
+  >>> f.close()
 
-The result of running ``h5dump`` on the file ``testfile3.hdf5`` should be:
+The result of running ``h5dump`` on the file ``testfile1.hdf5`` should be:
 
 .. code-block:: none
 
@@ -261,23 +261,49 @@ would return a 1D uint8 array instead of a 2D array.
 Pythonic operations on HDF5 files
 ---------------------------------
 
-You can use some Pythonic opertations on :py:class:`bob.io.base.HDF5File`.
-You can iterate over :py:class:`bob.io.base.HDF5File` objects to get an
-iterable of keys instead of calling
-:py:meth:`bob.io.base.HDF5File.keys`. You can also use the ``in`` keyword
-instead of calling :py:meth:`bob.io.base.HDF5File.has_key`. For example:
+You can use some Pythonic opertations on :py:class:`bob.io.base.HDF5File`:
+
+* Use the ``with`` statement to open (and automatically close) HDF5 files.
+* iterate over :py:class:`bob.io.base.HDF5File` objects to get an
+  iterable of keys instead of calling :py:meth:`bob.io.base.HDF5File.keys`.
+* use the ``in`` keyword instead of calling
+  :py:meth:`bob.io.base.HDF5File.has_key`.
+* use Python's dictionary syntax instead of :py:meth:`bob.io.base.HDF5File.set`
+  and :py:meth:`bob.io.base.HDF5File.get`.
+
+For example:
+
 
 .. doctest::
 
-  >>> keys = f.keys() # Get a list of keys
-  >>> keys == [key for key in f] # instead you can also iterate over keys
-  True
-  >>> f.has_key('arrayset')
+  >>> f = bob.io.base.HDF5File('testfile3.hdf5', 'w')
+  >>> array = numpy.arange(5)
+  >>> f['my_array'] = array # f.set('my_array', array)
+  >>> f['my_array'] # f.get('my_array')
+  array([0, 1, 2, 3, 4])
+  >>> 'my_array' in f # f.has_key('my_array')
   True
-  >>> 'arrayset' in f # you can use the `in` operator instead of `has_key`
+  >>> [key for key in f] # f.keys()
+  ['/my_array']
+  >>> f.create_group('group1')
+  >>> f.cd('group1')
+  >>> f['my_array_in_group'] = array
+  >>> f.cd('/')
+  >>> # keys(), values(), and items() just like a dictionary
+  >>> [key for key in f.keys()]
+  ['/my_array', '/group1/my_array_in_group']
+  >>> [value for value in f.values()]
+  [array([0, 1, 2, 3, 4]), array([0, 1, 2, 3, 4])]
+  >>> [(key, value) for key, value in f.items()]
+  [('/my_array', array([0, 1, 2, 3, 4])), ('/group1/my_array_in_group', array([0, 1, 2, 3, 4]))]
+  >>> f.close()
+  >>> # using a with statement to open and close files
+  >>> with bob.io.base.HDF5File('testfile3.hdf5', 'a') as f:
+  ...   f['second_array'] = array
+  >>> f = bob.io.base.HDF5File('testfile3.hdf5', 'r')
+  >>> 'second_array' in f
   True
 
-
 Array interfaces
 ----------------
 
@@ -356,35 +382,6 @@ the :py:class:`bob.io.base.File` container:
   the read and write operations. Have a look at the manual section for
   :py:mod:`bob.io.base` for more details and other shortcuts available.
 
-.. _audiosignal:
-
-Loading and saving audio files
-------------------------------
-
-|project| does not yet support audio files (no wav codec). However, it is
-possible to use the `SciPy`_ module :py:mod:`scipy.io.wavfile` to do the job.
-For instance, to read a wave file, just use the
-:py:func:`scipy.io.wavfile.read` function.
-
-.. code-block:: python
-
-   >>> import scipy.io.wavfile
-   >>> filename = '/home/user/sample.wav'
-   >>> samplerate, data = scipy.io.wavfile.read(filename)
-   >>> print(type(data))
-   <... 'numpy.ndarray'>
-   >>> print(data.shape)
-   (132474, 2)
-
-In the above example, the stereo audio signal is represented as a 2D `NumPy`
-:py:class:`numpy.ndarray`. The first dimension corresponds to the time index
-(132474 frames) and the second dimesnion correpsonds to one of the audio
-channel (2 channels, stereo). The values in the array correpsond to the wave
-magnitudes.
-
-To save a `NumPy` :py:class:`numpy.ndarray` into a wave file, the
-:py:func:`scipy.io.wavfile.write` could be used, which also requires the
-framerate to be specified.
 
 .. Place here your external references
 .. include:: links.rst
diff --git a/doc/py_api.rst b/doc/py_api.rst
index 47fdfaab8236b008e4121d92db9528bfdd4da6ff..bd8a9a713b3346583274afbca3bbb92306cf8ddf 100644
--- a/doc/py_api.rst
+++ b/doc/py_api.rst
@@ -49,5 +49,4 @@ Details
 .. automodule:: bob.io.base
    :inherited-members:
 
-
 .. automodule:: bob.io.base.test_utils