Allow operator overloading for custom classes to return custom objects
Uses a similar convention as numpy's ufunc overriding mechanism (https://docs.scipy.org/doc/numpy-1.13.0/neps/ufunc-overrides.html) to fix #22255

- [x] closes #22255
- [ ] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry
