<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class PDMixIn(object):

    @property
    def _constructor(self):
        return self.__class__

class DF(PDMixIn, pd.DataFrame):
    _metadata = ['my_prop']

    def __init__(self, *args, **kwargs):
        my_prop = kwargs.pop('my_prop', 'some_prop')
        super().__init__(*args, *kwargs)
        self.my_prop = my_prop

df = DF(my_prop='new_prop')
print(df.my_prop)
# 'new_prop' 

# But after adding 1
df = df + 1
print(df.my_prop)
# 'some_prop'"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-v">PDMixIn</span>(<span class="pl-s1">object</span>):

    <span class="pl-en">@<span class="pl-s1">property</span></span>
    <span class="pl-k">def</span> <span class="pl-en">_constructor</span>(<span class="pl-s1">self</span>):
        <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-s1">__class__</span>

<span class="pl-k">class</span> <span class="pl-v">DF</span>(<span class="pl-v">PDMixIn</span>, <span class="pl-s1">pd</span>.<span class="pl-v">DataFrame</span>):
    <span class="pl-s1">_metadata</span> <span class="pl-c1">=</span> [<span class="pl-s">'my_prop'</span>]

    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-c1">*</span><span class="pl-s1">args</span>, <span class="pl-c1">**</span><span class="pl-s1">kwargs</span>):
        <span class="pl-s1">my_prop</span> <span class="pl-c1">=</span> <span class="pl-s1">kwargs</span>.<span class="pl-en">pop</span>(<span class="pl-s">'my_prop'</span>, <span class="pl-s">'some_prop'</span>)
        <span class="pl-en">super</span>().<span class="pl-en">__init__</span>(<span class="pl-c1">*</span><span class="pl-s1">args</span>, <span class="pl-c1">*</span><span class="pl-s1">kwargs</span>)
        <span class="pl-s1">self</span>.<span class="pl-s1">my_prop</span> <span class="pl-c1">=</span> <span class="pl-s1">my_prop</span>

<span class="pl-s1">df</span> <span class="pl-c1">=</span> <span class="pl-v">DF</span>(<span class="pl-s1">my_prop</span><span class="pl-c1">=</span><span class="pl-s">'new_prop'</span>)
<span class="pl-en">print</span>(<span class="pl-s1">df</span>.<span class="pl-s1">my_prop</span>)
<span class="pl-c"># 'new_prop' </span>

<span class="pl-c"># But after adding 1</span>
<span class="pl-s1">df</span> <span class="pl-c1">=</span> <span class="pl-s1">df</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span>
<span class="pl-en">print</span>(<span class="pl-s1">df</span>.<span class="pl-s1">my_prop</span>)
<span class="pl-c"># 'some_prop'</span></pre></div>
<p dir="auto">Seems like DF is losing property value after addition I found similar behaviour for <strong>sub</strong> and others.</p>
<p dir="auto">I was able to solve the problem by adding following code to PDMixIn</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="def __add__(self, other):
        result = pd.DataFrame.__add__(self, other)
        return self._constructor(result).__finalize__(self)

df = df + 1
print(df.my_prop)
# 'new_prop'"><pre class="notranslate"><span class="pl-k">def</span> <span class="pl-en">__add__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>):
        <span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-s1">pd</span>.<span class="pl-v">DataFrame</span>.<span class="pl-en">__add__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">other</span>)
        <span class="pl-k">return</span> <span class="pl-s1">self</span>.<span class="pl-en">_constructor</span>(<span class="pl-s1">result</span>).<span class="pl-en">__finalize__</span>(<span class="pl-s1">self</span>)

<span class="pl-s1">df</span> <span class="pl-c1">=</span> <span class="pl-s1">df</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span>
<span class="pl-en">print</span>(<span class="pl-s1">df</span>.<span class="pl-s1">my_prop</span>)
<span class="pl-c"># 'new_prop'</span></pre></div>
<details>
<h2 dir="auto">INSTALLED VERSIONS</h2>
<p dir="auto">commit: None<br>
python: 3.6.3.final.0<br>
python-bits: 64<br>
OS: Windows<br>
OS-release: 10<br>
machine: AMD64<br>
processor: Intel64 Family 6 Model 78 Stepping 3, GenuineIntel<br>
byteorder: little<br>
LC_ALL: None<br>
LANG: en_US.UTF-8<br>
LOCALE: None.None</p>
<p dir="auto">pandas: 0.22.0<br>
pytest: 3.3.0<br>
pip: 9.0.1<br>
setuptools: 36.5.0.post20170921<br>
Cython: 0.27.3<br>
numpy: 1.13.3<br>
scipy: 1.0.0<br>
pyarrow: None<br>
xarray: None<br>
IPython: 6.2.1<br>
sphinx: 1.6.3<br>
patsy: 0.4.1<br>
dateutil: 2.6.1<br>
pytz: 2017.3<br>
blosc: None<br>
bottleneck: 1.2.1<br>
tables: 3.4.2<br>
numexpr: 2.6.4<br>
feather: None<br>
matplotlib: 2.1.1<br>
openpyxl: 2.4.9<br>
xlrd: 1.1.0<br>
xlwt: 1.3.0<br>
xlsxwriter: 1.0.2<br>
lxml: 4.1.1<br>
bs4: 4.6.0<br>
html5lib: 1.0.1<br>
sqlalchemy: 1.1.13<br>
pymysql: None<br>
psycopg2: 2.7.3.2 (dt dec pq3 ext lo64)<br>
jinja2: 2.10<br>
s3fs: None<br>
fastparquet: None<br>
pandas_gbq: None<br>
pandas_datareader: None</p>
</details>
<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>