ENH: Make DataFrame.insert more flexible
``DataFrame.insert`` is very inflexible today and can not really be used in pipes. I'd like to do several changes to the method:

* Add a inplace parameter, so the result from the op can be returned.
* allow a callable for ``value``, so the new values can be computed from existing column values.
* allow a dict for ``value``, so the several columns can be inserted simultaneously,
* add ``insert_after`` and ``insert_before`` parameters to allow label-based insertion location.
* move ``loc``  to the after ``value`` and let it have a default value of None, i.e. insert the new column at the end of the frame if location is not specified.
* deprecate ``DataFrame.assign``. It's functionality would be covered by the changed ``DataFrame.insert`` method.

The above change would allow us to be quite flexible when creating new columns in pipes. For example we could do
```python
df.insert("formal_name", lambda: "Mr. " + x["last_name"], insert_after="last_name")
.pipe(...)
```

The above is obviously quite a large change. It could be discussed if it would be better make it a new method instead of changing an existing one...