<p dir="auto">Looking at core.ops. _comp_method_SERIES and whether we can have the datetime and timedelta cases defer to Index subclass implementations, a couple questions come up:</p>
<p dir="auto"><a href="https://github.com/pandas-dev/pandas/blob/master/pandas/core/ops.py#L744">https://github.com/pandas-dev/pandas/blob/master/pandas/core/ops.py#L744</a></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    def na_op(x, y):
        # dispatch to the categorical if we have a categorical
        # in either operand
        if is_categorical_dtype(x):
            return op(x, y)
        elif is_categorical_dtype(y) and not is_scalar(y):
            return op(y, x)"><pre class="notranslate"><code class="notranslate">    def na_op(x, y):
        # dispatch to the categorical if we have a categorical
        # in either operand
        if is_categorical_dtype(x):
            return op(x, y)
        elif is_categorical_dtype(y) and not is_scalar(y):
            return op(y, x)
</code></pre></div>
<p dir="auto">This <code class="notranslate">return op(y, x)</code> looks weird.  Should it be a reverse-op?  e.g if op is operator.ge, should this become <code class="notranslate">return operator.le(y, x)</code>?  Maybe this is irrelevant if categorical comparisons are only defined for <code class="notranslate">__eq__</code> and <code class="notranslate">__ne__</code>?  If that is the explanation, there should be a comment.</p>
<p dir="auto"><a href="https://github.com/pandas-dev/pandas/blob/master/pandas/core/ops.py#L812">Special casing</a> for PeriodIndex:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="            if isinstance(other, ABCPeriodIndex):
                # temp workaround until fixing GH 13637
                # tested in test_nat_comparisons
                # (pandas.tests.series.test_operators.TestSeriesOperators)
                return self._constructor(na_op(self.values,
                                               other.astype(object).values),
                                         index=self.index)"><pre class="notranslate"><code class="notranslate">            if isinstance(other, ABCPeriodIndex):
                # temp workaround until fixing GH 13637
                # tested in test_nat_comparisons
                # (pandas.tests.series.test_operators.TestSeriesOperators)
                return self._constructor(na_op(self.values,
                                               other.astype(object).values),
                                         index=self.index)
</code></pre></div>
<p dir="auto">I couldn't tell from <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="165233792" data-permission-text="Title is private" data-url="https://github.com/pandas-dev/pandas/issues/13637" data-hovercard-type="issue" data-hovercard-url="/pandas-dev/pandas/issues/13637/hovercard" href="https://github.com/pandas-dev/pandas/issues/13637">#13637</a> what the connection was.  Commenting this out did not appear to break anything in the tests.  Anyone know if this is still relevant?</p>
<p dir="auto"><b>Update</b> I forgot to mention the question mentioned in the Issue title.  Most cases return <code class="notranslate">self._constructor(res, index=self.index, name=whatever)</code>, but <a href="https://github.com/pandas-dev/pandas/blob/master/pandas/core/ops.py#L821">one case</a> returns <code class="notranslate">self._constructor(na_op(self.values, np.asarray(other)), index=self.index).__finalize__(self)</code>.  Why is <code class="notranslate">__finalize__</code> called in this case but not others?</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#!/bin/env python
&quot;&quot;&quot;
Example bug in derived Pandas Series.

__finalized__ is not called in arithmetic binary operators, but it is in in some booleans cases.

&gt;&gt;&gt; m = MySeries([1, 2, 3], name='test')
&gt;&gt;&gt; m.x = 42
&gt;&gt;&gt; n=m[:2]
&gt;&gt;&gt; n
0    1
1    2
dtype: int64
&gt;&gt;&gt; n.x
42
&gt;&gt;&gt; o=n+1
&gt;&gt;&gt; o
0    2
1    3
dtype: int64
&gt;&gt;&gt; o.x
Traceback (most recent call last):
        ...
AttributeError: 'MySeries' object has no attribute 'x'
&gt;&gt;&gt; m = MySeries([True, False, True], name='test2')
&gt;&gt;&gt; m.x = 42
&gt;&gt;&gt; n=m[:2]
&gt;&gt;&gt; n
0     True
1    False
dtype: bool
&gt;&gt;&gt; n.x
42
&gt;&gt;&gt; o=n ^ True
&gt;&gt;&gt; o
0    False
1     True
dtype: bool
&gt;&gt;&gt; o.x
42
&gt;&gt;&gt; p = n ^ o
&gt;&gt;&gt; p
0    True
1    True
dtype: bool
&gt;&gt;&gt; p.x
42

&quot;&quot;&quot;

import pandas as pd

class MySeries(pd.Series):
    _metadata = ['x']

    @property
    def _constructor(self):
        return MySeries

if __name__ == &quot;__main__&quot;:
    import doctest
    doctest.testmod()
"><pre class="notranslate"><code class="notranslate">#!/bin/env python
"""
Example bug in derived Pandas Series.

__finalized__ is not called in arithmetic binary operators, but it is in in some booleans cases.

&gt;&gt;&gt; m = MySeries([1, 2, 3], name='test')
&gt;&gt;&gt; m.x = 42
&gt;&gt;&gt; n=m[:2]
&gt;&gt;&gt; n
0    1
1    2
dtype: int64
&gt;&gt;&gt; n.x
42
&gt;&gt;&gt; o=n+1
&gt;&gt;&gt; o
0    2
1    3
dtype: int64
&gt;&gt;&gt; o.x
Traceback (most recent call last):
        ...
AttributeError: 'MySeries' object has no attribute 'x'
&gt;&gt;&gt; m = MySeries([True, False, True], name='test2')
&gt;&gt;&gt; m.x = 42
&gt;&gt;&gt; n=m[:2]
&gt;&gt;&gt; n
0     True
1    False
dtype: bool
&gt;&gt;&gt; n.x
42
&gt;&gt;&gt; o=n ^ True
&gt;&gt;&gt; o
0    False
1     True
dtype: bool
&gt;&gt;&gt; o.x
42
&gt;&gt;&gt; p = n ^ o
&gt;&gt;&gt; p
0    True
1    True
dtype: bool
&gt;&gt;&gt; p.x
42

"""

import pandas as pd

class MySeries(pd.Series):
    _metadata = ['x']

    @property
    def _constructor(self):
        return MySeries

if __name__ == "__main__":
    import doctest
    doctest.testmod()

</code></pre></div>
<h4 dir="auto">Expected Output</h4>
<p dir="auto">In all cases, the metadata 'x' should be transferred from the passed values when applying binary operators.<br>
When the right-hand value is a constant, the left-hand value metadata should be used in <strong>finalize</strong> for arithmetic operators, just like it is for Boolean binary operators.<br>
When two series are used in binary operators, some resolution should be possible in <strong>finalize</strong>.<br>
I would pass the second (right-hand) value by calling <strong>finalize</strong>(self, other=other), leaving the resolution to the derived class implementer, but there might be a smarter approach.</p>
<h4 dir="auto">output of <code class="notranslate">pd.show_versions()</code></h4>
<p dir="auto">pd.show_versions()</p>
<h2 dir="auto">INSTALLED VERSIONS</h2>
<p dir="auto">commit: None<br>
python: 2.7.6.final.0<br>
python-bits: 64<br>
OS: Linux<br>
OS-release: 3.19.0-59-generic<br>
machine: x86_64<br>
processor: x86_64<br>
byteorder: little<br>
LC_ALL: None<br>
LANG: en_US.UTF-8</p>
<p dir="auto">pandas: 0.18.1<br>
nose: 1.3.7<br>
pip: None<br>
setuptools: 20.2.2<br>
Cython: 0.24<br>
numpy: 1.11.0<br>
scipy: 0.17.0<br>
statsmodels: 0.6.1<br>
xarray: None<br>
IPython: 4.0.1<br>
sphinx: 1.3.1<br>
patsy: 0.4.0<br>
dateutil: 2.4.2<br>
pytz: 2015.7<br>
blosc: None<br>
bottleneck: 1.0.0<br>
tables: 3.2.2<br>
numexpr: 2.5.2<br>
matplotlib: 1.5.0<br>
openpyxl: 2.2.6<br>
xlrd: 0.9.4<br>
xlwt: 1.0.0<br>
xlsxwriter: 0.7.7<br>
lxml: 3.4.4<br>
bs4: 4.4.1<br>
html5lib: 0.9999999<br>
httplib2: None<br>
apiclient: None<br>
sqlalchemy: 1.0.9<br>
pymysql: None<br>
psycopg2: None<br>
jinja2: 2.8<br>
boto: 2.38.0<br>
pandas_datareader: None</p>