Making all attributes on Key read-only and sorts out use of setters.

Addresses second part of #451. In some cases, since no valid
replacements for setters are implemented here, the functionality
is replaced with hacks using protected methods.

Also added a getter for Key._dataset_id and made the Key.path
property return a copy since a `list` of `dict`s is very much
mutable.