Refactor kernel base class which can be inherited for wrapper kernels

This separates out the general kernel machinery (as `KernelBase`) from the IPython-specific kernel implementation. This allows third parties to inherit from `KernelBase` to implement custom kernels, and I've provided documentation on how to do this.

It also takes us closer to the 'comms only kernel' that could run on a public server to support interactive widgets - that would be another subclass of `KernelBase` that doesn't implement `do_execute`.
this PR looks great, just one little inconsistency which is that we refer to this as "object introspection" in the docs