De-duplicate dispatch code, remove unreachable branches
State: closed

There are a couple of `DataFrame` methods that operate column-wise, dispatching to `Series` implementations.  This de-duplicates that code by implementing `ops.dispatch_to_series`.  Importantly, this function is going to be used a few more times as we move towards getting rid of `BlockManager.eval` and `Block.eval`, so putting it in place now makes for a more focused diff later.

Also removes a couple of no-longer-reachable cases in comparison ops.

- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`



Labels:
name: Refactor
description: Internal refactoring of code
name: Algos
description: Non-arithmetic algos: value_counts, factorize, sorting, isin, clip, shift, diff

Comments:
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22068?src=pr&el=h1) Report
> Merging [#22068](https://codecov.io/gh/pandas-dev/pandas/pull/22068?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/647f3f091eedd715b7966829a36ef345de4d7a4d?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `95%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/22068/graphs/tree.svg?src=pr&token=eZ4WkYLtcO&width=650&height=150)](https://codecov.io/gh/pandas-dev/pandas/pull/22068?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #22068      +/-   ##
==========================================
+ Coverage   92.06%   92.06%   +<.01%     
==========================================
  Files         170      170              
  Lines       50720    50715       -5     
==========================================
- Hits        46694    46691       -3     
+ Misses       4026     4024       -2
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.47% <95%> (ø)` | :arrow_up: |
| #single | `42.3% <20%> (ø)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/22068?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/22068/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.24% <100%> (-0.02%)` | :arrow_down: |
| [pandas/core/ops.py](https://codecov.io/gh/pandas-dev/pandas/pull/22068/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvb3BzLnB5) | `96.46% <92.3%> (+0.31%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22068?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/22068?src=pr&el=footer). Last update [647f3f0...c36e672](https://codecov.io/gh/pandas-dev/pandas/pull/22068?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

pls rebase
looks fine. can you run an asv dataframe ops (or a subset of them) to ensure that perf is not materially different. and rebase on master (if its not already)
> and rebase on master (if its not already)

Sure

> can you run an asv dataframe ops (or a subset of them) to ensure that perf is not materially different

Will run, but there's nothing here that should affect anything.
Looks like frame-frame comparisons are non-trivially slower due to numexpr being used less effectively.  Specifically ATM dispatch-to-Series is done inside numexpr, while in the PR the dispatch is done outside numexpr.

```
asv continuous -f 1.1 -E virtualenv master HEAD -b dataframe -b DataFrame -b ops
[...]
       before           after         ratio
     [9c118668]       [94f168a8]
+      5.69±0.1ms         153±20ms    26.86  binary_ops.Ops.time_frame_comparison(True, 'default')
+      4.03±0.2ms         97.5±3ms    24.19  binary_ops.Ops.time_frame_comparison(True, 1)
+      17.8±0.2ms       27.3±0.3ms     1.54  join_merge.Join.time_join_dataframe_index_multi(False)
+      14.5±0.1ms         19.5±6ms     1.34  join_merge.Merge.time_merge_dataframe_integer_2key(True)
-        70.7±2ms         54.3±4ms     0.77  binary_ops.Ops.time_frame_comparison(False, 1)
-        72.7±4ms         51.0±2ms     0.70  binary_ops.Ops.time_frame_comparison(False, 'default')
```

For the time being I'll revert that part of the PR.
After reverting the numexpr thing:

```
taskset 5 asv continuous -f 1.1 -E virtualenv master HEAD -b time_frame_comparison
[...]
       before           after         ratio
     [9c118668]       [c36e6729]
-        66.6±3ms         48.7±2ms     0.73  binary_ops.Ops.time_frame_comparison(False, 'default')
-        71.5±5ms         49.1±2ms     0.69  binary_ops.Ops.time_frame_comparison(False, 1)

taskset 5 asv continuous -f 1.1 -E virtualenv master HEAD -b time_frame_comparison
[...]
       before           after         ratio
     [9c118668]       [c36e6729]
-        66.1±2ms         49.9±2ms     0.76  binary_ops.Ops.time_frame_comparison(False, 'default')

taskset 5 asv continuous -f 1.1 -E virtualenv master HEAD -b time_frame_comparison
[...]
       before           after         ratio
     [9c118668]       [c36e6729]
-        70.8±3ms         48.0±2ms     0.68  binary_ops.Ops.time_frame_comparison(False, 'default')
-        77.5±6ms         50.4±4ms     0.65  binary_ops.Ops.time_frame_comparison(False, 1)
```
see good thing we look at perf even when it *shouldn't* affect things :-D
thanks.