Is using type as dictionary keys considered good practice in Python?
<p>I have a lookup table like this:</p>

<pre><code>lookup = {
  "&lt;class 'Minority.mixin'&gt;": report_minority,
  "&lt;class 'Majority.mixin'&gt;": report_majority,
}

def report(o):
  h = lookup[str(type(o))]
  h()
</code></pre>

<p>It looks awkward to me as the <code>key</code> is precariously linked to how <code>type()</code> returns and represents a <code>class</code> in <code>string</code>. If one day Python changes its way to represents <code>class</code> types in <code>string</code>, all the codes like this are broken. So I want to have some advice from pros, is such type of keys considered good or bad? Thanks.</p>

<p>The question would more be <em>why are you doing this in the first place</em>? What advantage do <em>you</em> think using strings has?</p>

<p>Class objects are hashable, so you can use <code>Minority.mixin</code> and <code>Majority.mixin</code> <em>directly</em> as keys. And when you do so, you ensure that the key is <em>always</em> the exact same object provided your classes are globals in their respective modules, making them singletons your program. Moreover, there is no chance of accidental confusion when you later on refactor your code to rename modules and you end up with a <em>different</em> type with that exact <code>repr()</code> output.</p>

<p>So unless you have a specific usecase where you <em>can't</em> use the class directly, you should not be using the string representations.</p>

<p>(And even if you were to generate classes with a factory function, using a baseclass and <code>isinstance</code> checks or extracting a base class from the MRO would probably be preferable).</p>

<p>So, for your usecase, stick to:</p>

<pre><code>lookup = {
    Minority.mixin: report_minority,
    Majority.mixin: report_majority,
}

def report(o):
    h = lookup[type(o)])
    h()
</code></pre>

<p>Next, if you ensure that <code>report_minority</code> and <code>report_majority</code> are <em>functions</em> (and not methods, for example), you can use <a href="https://docs.python.org/3/library/functools.html#functools.singledispatch" rel="nofollow"><code>functools.singledispatch()</code></a> and dispense with your mapping altogether:</p>

<pre><code>from functools import singledispatch

@singledispatch
def report(o):
    raise ValueError('Unhandled type {}'.format(type(o)))

@report.register(Minority.mixin)
def report_minority(o):
    # handle a Minority instance

@report.register(Majority.mixin)
def report_majority(o):
    # handle a Majority instance
</code></pre>

<p>Note that this won't work with methods, as methods have to take multiple arguments for dispatch to work, as they always take <code>self</code>.</p>

<p>Single-dispatch handles <em>subclasses</em> much better, unlike your <code>str</code>-based mapping or even the direct class mapping.</p>

python python-3.x dictionary