Where's the logic that returns an instance of a subclass of OSError exception class?
<p>I've been hunting for something that could be relatively stupid to some people, but to me very interesting! :-)</p>

<p>Input and output errors have been merged with <code>OSError</code> in Python 3.3, so there's a change in the exception class hierarchy. One interesting feature about the builtin class <code>OSError</code> is that, it returns a subclass of it when passed <code>errno</code> and <code>strerror</code></p>

<pre><code>&gt;&gt;&gt; OSError(2, os.strerror(2))
FileNotFoundError(2, 'No such file or directory')

&gt;&gt;&gt; OSError(2, os.strerror(2)).errno
2
&gt;&gt;&gt; OSError(2, os.strerror(2)).strerror
'No such file or directory'
</code></pre>

<p>As you can see passing <code>errno</code> and <code>strerror</code> to the constructor of <code>OSError</code> returns <code>FileNotFoundError</code> instance which is a subclass of <code>OSError</code>.</p>

<p><em>Python Doc:</em> </p>

<blockquote>
  <p>The constructor often actually returns a subclass of OSError, as described in OS <a href="https://docs.python.org/3/library/exceptions.html#os-exceptions" rel="nofollow">exceptions</a> below. The particular subclass depends on the final errno value. <strong>This behaviour only occurs when constructing OSError directly or via an alias, and is not inherited when subclassing.</strong></p>
</blockquote>

<p>I wanted to code a subclass that would behave in this way. It's mostly curiosity and not real world code. I'm also trying to know, where's the logic that creates the subclass object, is it coded in <code>__new__</code> for example? If <code>__new__</code> contains the logic for creating the instances of the subclasses, then inheriting from <code>OSError</code> would typically return this behavior, unless if there's some sort of type checking in <code>__new__</code>:</p>

<pre><code>&gt;&gt;&gt; class A(OSError): pass 
&gt;&gt;&gt; A(2, os.strerror(2))
A(2, 'No such file or directory')
</code></pre>

<p>There must be type checking then: </p>

<pre><code># If passed OSError, returns subclass instance
&gt;&gt;&gt; A.__new__(OSError, 2, os.strerror(2))         
FileNotFoundError(2, 'No such file or directory')

# Not OSError? Return instance of A
&gt;&gt;&gt; A.__new__(A, 2, os.strerror(2)
A(2, 'No such file or directory')
</code></pre>

<p>I've been digging through C code to find out where's this code is placed exactly and since I'm not an expert in C, I suspect this is really the logic and (I'm quite skeptical about that to be frank): </p>

<p><a href="https://hg.python.org/cpython/file/5ae8756a1ae0/Objects/exceptions.c" rel="nofollow">exceptions.c</a></p>

<pre><code>if (myerrno &amp;&amp; PyLong_Check(myerrno) &amp;&amp;
    errnomap &amp;&amp; (PyObject *) type == PyExc_OSError) {
    PyObject *newtype;
    newtype = PyDict_GetItem(errnomap, myerrno);
    if (newtype) {
        assert(PyType_Check(newtype));
        type = (PyTypeObject *) newtype;
    }
    else if (PyErr_Occurred())
        goto error;
}
}
</code></pre>

<p>Now I'm wondering about the possibility of expanding <code>errnomap</code> from Python itself without playing with C code, so that <code>OSErro</code> can make instances of user-defined classes, if you ask me why would you do that? I would say, just for fun. </p>

<p>You can't change the behavior of <code>OSError</code> from Python because it's not implemented in Python.</p>

<p>For classes implemented in Python, you can write <code>__new__</code> so it only returns a subclass if it's being called on the base class. Then the behavior won't be inherited.</p>

<pre><code>class MyClass(object):
    def __new__(cls, sub=0, _subtypes={}):
        if cls is MyClass:
             if sub not in _subtypes:
                 _subtypes[sub] = type("MyClass(%s)" % sub, (MyClass,), {})
             return _subtypes[sub](sub)
        return object.__new__(cls, sub)
    def __init__(self, sub):
        assert type(self).__name__ == "MyClass(%s)" % sub

class SubClass(MyClass):
     def __init__(self, sub=None):
         assert type(self).__name__ == "SubClass"

print(MyClass(1))    # &lt;__main__.MyClass(1) object at 0x01EB1EB0&gt;
print(SubClass())    # &lt;__main__.SubClass object at 0x01EB1CD0&gt;
</code></pre>

python