<p dir="auto"><code class="notranslate">pd.NaT</code> is an instance of <code class="notranslate">NaTType</code>.  <code class="notranslate">NaTType</code> inherits from <code class="notranslate">_NaT</code>, which inherits from <code class="notranslate">_Timestamp</code>, which inherits from <code class="notranslate">datetime</code>.</p>
<p dir="auto">How would people feel about taking <code class="notranslate">_Timestamp</code> out of that chain?  Note that <code class="notranslate">_Timestamp</code> is not exported, so no users should be checking e.g. <code class="notranslate">isinstance(x, _Timestamp)</code>.</p>
<p dir="auto">The motivation: if we can take <code class="notranslate">_Timestamp</code> out of the inheritance chain, then the entire <code class="notranslate">NaT</code> hierarchy along with the instance itself can be defined in its own dedicated module, with no intra-pandas dependencies other than <code class="notranslate">util</code>.  This comes out to a little over 500 lines.</p>
<p dir="auto">This opens up opportunities for simplification elsewhere, since there are a <em>bunch</em> of modules that import <code class="notranslate">NaT</code> but don't care about most of the rest of <code class="notranslate">tslib</code> (the same applies to the timezones functions in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="251054685" data-permission-text="Title is private" data-url="https://github.com/pandas-dev/pandas/issues/17274" data-hovercard-type="pull_request" data-hovercard-url="/pandas-dev/pandas/pull/17274/hovercard" href="https://github.com/pandas-dev/pandas/pull/17274">#17274</a>).  Of particular interest are <code class="notranslate">_libs.lib</code>, <code class="notranslate">_libs.period</code>, <code class="notranslate">tseries.frequencies</code>, and <code class="notranslate">tseries.offsets</code>.</p>
<p dir="auto">The other upside is that with few dependencies, the module becomes much easier to test/benchmark/maintain.</p>
<p dir="auto">Without <code class="notranslate">_NaT</code> inheriting from <code class="notranslate">_Timestamp</code>, a methods in <code class="notranslate">_Timestamp</code> become eligible for the <code class="notranslate">@cython.final</code> decorator.  My (limited) understanding is that this provides a small performance improvement.</p>
<p dir="auto">The main downside I see is that the docstring pinning done by <code class="notranslate">_make_error_func</code>, <code class="notranslate">_make_nat_func</code>, and <code class="notranslate">_make_nan_func</code> is a bit of a hassle.</p>
<h4 dir="auto">Code Sample, a copy-pastable example if possible</h4>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [2]: mi = pd.MultiIndex.from_product([['i'], ['ii'], ['iii']])

In [3]: mi.rename([1,5,6]).get_level_values(1) # Interpreted as label
Out[3]: Index(['i'], dtype='object', name=1)

In [4]: mi.rename([1,5,1]).get_level_values(1) # Interpreted as index
Out[4]: Index(['ii'], dtype='object', name=5)

In [5]: mi.rename(['a',5,'a']).get_level_values('a') # ValueError is OK, KeyError is not
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/home/nobackup/repo/pandas/pandas/core/indexes/multi.py in _get_level_number(self, level)
    670                 raise ValueError('The name %s occurs multiple times, use a '
--&gt; 671                                  'level number' % level)
    672             level = self.names.index(level)

ValueError: The name a occurs multiple times, use a level number

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
&lt;ipython-input-5-e8a616f9610f&gt; in &lt;module&gt;()
----&gt; 1 mi.rename(['a',5,'a']).get_level_values('a')

/home/nobackup/repo/pandas/pandas/core/indexes/multi.py in get_level_values(self, level)
    975         Index(['d', 'e', 'f'], dtype='object', name='level_2')
    976         &quot;&quot;&quot;
--&gt; 977         level = self._get_level_number(level)
    978         values = self._get_level_values(level)
    979         return values

/home/nobackup/repo/pandas/pandas/core/indexes/multi.py in _get_level_number(self, level)
    673         except ValueError:
    674             if not isinstance(level, int):
--&gt; 675                 raise KeyError('Level %s not found' % str(level))
    676             elif level &lt; 0:
    677                 level += self.nlevels

KeyError: 'Level a not found'

In [6]: mi.rename([1, 'a', 'a']).get_level_values(1) # How am I going to access the second level?!
Out[6]: Index(['i'], dtype='object', name=1)
"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">2</span>]: <span class="pl-s1">mi</span> <span class="pl-c1">=</span> <span class="pl-s1">pd</span>.<span class="pl-v">MultiIndex</span>.<span class="pl-en">from_product</span>([[<span class="pl-s">'i'</span>], [<span class="pl-s">'ii'</span>], [<span class="pl-s">'iii'</span>]])

<span class="pl-v">In</span> [<span class="pl-c1">3</span>]: <span class="pl-s1">mi</span>.<span class="pl-en">rename</span>([<span class="pl-c1">1</span>,<span class="pl-c1">5</span>,<span class="pl-c1">6</span>]).<span class="pl-en">get_level_values</span>(<span class="pl-c1">1</span>) <span class="pl-c"># Interpreted as label</span>
<span class="pl-v">Out</span>[<span class="pl-c1">3</span>]: <span class="pl-v">Index</span>([<span class="pl-s">'i'</span>], <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'object'</span>, <span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-c1">1</span>)

<span class="pl-v">In</span> [<span class="pl-c1">4</span>]: <span class="pl-s1">mi</span>.<span class="pl-en">rename</span>([<span class="pl-c1">1</span>,<span class="pl-c1">5</span>,<span class="pl-c1">1</span>]).<span class="pl-en">get_level_values</span>(<span class="pl-c1">1</span>) <span class="pl-c"># Interpreted as index</span>
<span class="pl-v">Out</span>[<span class="pl-c1">4</span>]: <span class="pl-v">Index</span>([<span class="pl-s">'ii'</span>], <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'object'</span>, <span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-c1">5</span>)

<span class="pl-v">In</span> [<span class="pl-c1">5</span>]: <span class="pl-s1">mi</span>.<span class="pl-en">rename</span>([<span class="pl-s">'a'</span>,<span class="pl-c1">5</span>,<span class="pl-s">'a'</span>]).<span class="pl-en">get_level_values</span>(<span class="pl-s">'a'</span>) <span class="pl-c"># ValueError is OK, KeyError is not</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">ValueError</span>                                <span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>)
<span class="pl-c1">/</span><span class="pl-s1">home</span><span class="pl-c1">/</span><span class="pl-s1">nobackup</span><span class="pl-c1">/</span><span class="pl-s1">repo</span><span class="pl-c1">/</span><span class="pl-s1">pandas</span><span class="pl-c1">/</span><span class="pl-s1">pandas</span><span class="pl-c1">/</span><span class="pl-s1">core</span><span class="pl-c1">/</span><span class="pl-s1">indexes</span><span class="pl-c1">/</span><span class="pl-s1">multi</span>.<span class="pl-s1">py</span> <span class="pl-c1">in</span> <span class="pl-en">_get_level_number</span>(<span class="pl-s1">self</span>, <span class="pl-s1">level</span>)
    <span class="pl-c1">670</span>                 <span class="pl-k">raise</span> <span class="pl-v">ValueError</span>(<span class="pl-s">'The name %s occurs multiple times, use a '</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">&gt;</span> <span class="pl-c1">671</span>                                  <span class="pl-s">'level number'</span> <span class="pl-c1">%</span> <span class="pl-s1">level</span>)
    <span class="pl-c1">672</span>             <span class="pl-s1">level</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-s1">names</span>.<span class="pl-en">index</span>(<span class="pl-s1">level</span>)

<span class="pl-v">ValueError</span>: <span class="pl-v">The</span> <span class="pl-s1">name</span> <span class="pl-s1">a</span> <span class="pl-s1">occurs</span> <span class="pl-s1">multiple</span> <span class="pl-s1">times</span>, <span class="pl-s1">use</span> <span class="pl-s1">a</span> <span class="pl-s1">level</span> <span class="pl-s1">number</span>

<span class="pl-v">During</span> <span class="pl-s1">handling</span> <span class="pl-s1">of</span> <span class="pl-s1">the</span> <span class="pl-s1">above</span> <span class="pl-s1">exception</span>, <span class="pl-s1">another</span> <span class="pl-s1">exception</span> <span class="pl-s1">occurred</span>:

<span class="pl-v">KeyError</span>                                  <span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>)
<span class="pl-c1">&lt;</span><span class="pl-s1">ipython</span><span class="pl-c1">-</span><span class="pl-s1">input</span><span class="pl-c1">-</span><span class="pl-c1">5</span><span class="pl-c1">-</span><span class="pl-s1">e8a616f9610f</span><span class="pl-c1">&gt;</span> <span class="pl-s1">in</span> <span class="pl-c1">&lt;</span><span class="pl-s1">module</span><span class="pl-c1">&gt;</span>()
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">&gt;</span> <span class="pl-c1">1</span> <span class="pl-s1">mi</span>.<span class="pl-en">rename</span>([<span class="pl-s">'a'</span>,<span class="pl-c1">5</span>,<span class="pl-s">'a'</span>]).<span class="pl-en">get_level_values</span>(<span class="pl-s">'a'</span>)

<span class="pl-c1">/</span><span class="pl-s1">home</span><span class="pl-c1">/</span><span class="pl-s1">nobackup</span><span class="pl-c1">/</span><span class="pl-s1">repo</span><span class="pl-c1">/</span><span class="pl-s1">pandas</span><span class="pl-c1">/</span><span class="pl-s1">pandas</span><span class="pl-c1">/</span><span class="pl-s1">core</span><span class="pl-c1">/</span><span class="pl-s1">indexes</span><span class="pl-c1">/</span><span class="pl-s1">multi</span>.<span class="pl-s1">py</span> <span class="pl-c1">in</span> <span class="pl-en">get_level_values</span>(<span class="pl-s1">self</span>, <span class="pl-s1">level</span>)
    <span class="pl-c1">975</span>         <span class="pl-v">Index</span>([<span class="pl-s">'d'</span>, <span class="pl-s">'e'</span>, <span class="pl-s">'f'</span>], <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'object'</span>, <span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s">'level_2'</span>)
    <span class="pl-c1">976</span>         """
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">&gt;</span> <span class="pl-c1">977</span>         <span class="pl-s1">level</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-en">_get_level_number</span>(<span class="pl-s1">level</span>)
    <span class="pl-c1">978</span>         <span class="pl-s1">values</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-en">_get_level_values</span>(<span class="pl-s1">level</span>)
    <span class="pl-c1">979</span>         <span class="pl-s1">return</span> <span class="pl-s1">values</span>

<span class="pl-c1">/</span><span class="pl-s1">home</span><span class="pl-c1">/</span><span class="pl-s1">nobackup</span><span class="pl-c1">/</span><span class="pl-s1">repo</span><span class="pl-c1">/</span><span class="pl-s1">pandas</span><span class="pl-c1">/</span><span class="pl-s1">pandas</span><span class="pl-c1">/</span><span class="pl-s1">core</span><span class="pl-c1">/</span><span class="pl-s1">indexes</span><span class="pl-c1">/</span><span class="pl-s1">multi</span>.<span class="pl-s1">py</span> <span class="pl-c1">in</span> <span class="pl-en">_get_level_number</span>(<span class="pl-s1">self</span>, <span class="pl-s1">level</span>)
    <span class="pl-c1">673</span>         <span class="pl-s1">except</span> <span class="pl-v">ValueError</span>:
    <span class="pl-c1">674</span>             <span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">level</span>, <span class="pl-s1">int</span>):
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">&gt;</span> <span class="pl-c1">675</span>                 <span class="pl-s1">raise</span> <span class="pl-v">KeyError</span>(<span class="pl-s">'Level %s not found'</span> <span class="pl-c1">%</span> <span class="pl-en">str</span>(<span class="pl-s1">level</span>))
    <span class="pl-c1">676</span>             <span class="pl-s1">elif</span> <span class="pl-s1">level</span> <span class="pl-c1">&lt;</span> <span class="pl-c1">0</span>:
    <span class="pl-c1">677</span>                 <span class="pl-s1">level</span> <span class="pl-c1">+=</span> <span class="pl-s1">self</span>.<span class="pl-s1">nlevels</span>

<span class="pl-v">KeyError</span>: <span class="pl-s">'Level a not found'</span>

<span class="pl-v">In</span> [<span class="pl-c1">6</span>]: <span class="pl-s1">mi</span>.<span class="pl-en">rename</span>([<span class="pl-c1">1</span>, <span class="pl-s">'a'</span>, <span class="pl-s">'a'</span>]).<span class="pl-en">get_level_values</span>(<span class="pl-c1">1</span>) <span class="pl-c"># How am I going to access the second level?!</span>
<span class="pl-v">Out</span>[<span class="pl-c1">6</span>]: <span class="pl-v">Index</span>([<span class="pl-s">'i'</span>], <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'object'</span>, <span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-c1">1</span>)</pre></div>
<h4 dir="auto">Problem description</h4>
<p dir="auto">There are different problems, but the root cause is (I think) the same:</p>
<ol dir="auto">
<li>the first is trivial: the <code class="notranslate">KeyError</code> in <code class="notranslate">In [5]:</code> should not appear</li>
<li>the second is that the interpretation of an integer changes when there is a duplicate name (difference between <code class="notranslate">Out[3]</code> and <code class="notranslate">Out[4]</code>)</li>
<li>the third is that in a situation like <code class="notranslate">In [6]</code>, I have no way whatsoever to access the second column, since it is denoted by a duplicated name <em>and</em> its index is also the name of another column (sure, this is a perverse example, but I suspect it can bite in some cases in which users use duplicate labels <em>and</em> pandas internal code adds integer labels)</li>
</ol>
<h4 dir="auto">Expected Output</h4>
<p dir="auto">If we were to design this from scratch, the solution would be simple: prioritize the "index" interpretation of an integer over the "label" interpretation, so that the former is always unambiguous. Is this a too strong API change?</p>
<p dir="auto">If the answer is "no", I will be happy to implement it, possibly with a temporary warning in those cases where the behaviour will change (that is: requested label is integer <em>and</em> is present in the names).</p>
<p dir="auto">If the answer is "yes", I would like to at least suppress the <code class="notranslate">KeyError</code> in <code class="notranslate">In [5]:</code> and have <code class="notranslate">In [4]:</code> raise an error rather than return a result inconsistent with <code class="notranslate">In [3]:</code>.</p>
<h4 dir="auto">Output of <code class="notranslate">pd.show_versions()</code></h4>
<details>
<h2 dir="auto">INSTALLED VERSIONS</h2>
<p dir="auto">commit: <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/pandas-dev/pandas/commit/04db779d4c93d286bb0ab87780a85d50ec490266/hovercard" href="https://github.com/pandas-dev/pandas/commit/04db779d4c93d286bb0ab87780a85d50ec490266"><tt>04db779</tt></a><br>
python: 3.5.3.final.0<br>
python-bits: 64<br>
OS: Linux<br>
OS-release: 4.9.0-4-amd64<br>
machine: x86_64<br>
processor:<br>
byteorder: little<br>
LC_ALL: None<br>
LANG: it_IT.UTF-8<br>
LOCALE: it_IT.UTF-8</p>
<p dir="auto">pandas: 0.22.0.dev0+388.g04db779d4<br>
pytest: 3.2.3<br>
pip: 9.0.1<br>
setuptools: 36.7.0<br>
Cython: 0.25.2<br>
numpy: 1.12.1<br>
scipy: 0.19.0<br>
pyarrow: None<br>
xarray: None<br>
IPython: 6.2.1<br>
sphinx: 1.5.6<br>
patsy: 0.4.1<br>
dateutil: 2.6.1<br>
pytz: 2017.2<br>
blosc: None<br>
bottleneck: 1.2.0dev<br>
tables: 3.3.0<br>
numexpr: 2.6.1<br>
feather: 0.3.1<br>
matplotlib: 2.0.0<br>
openpyxl: 2.3.0<br>
xlrd: 1.0.0<br>
xlwt: 1.3.0<br>
xlsxwriter: 0.9.6<br>
lxml: 4.1.1<br>
bs4: 4.5.3<br>
html5lib: 0.999999999<br>
sqlalchemy: 1.0.15<br>
pymysql: None<br>
psycopg2: None<br>
jinja2: 2.10<br>
s3fs: None<br>
fastparquet: None<br>
pandas_gbq: None<br>
pandas_datareader: 0.2.1</p>
</details>