<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _get_type_name(target_thing):
 """ Functions, bound methods and unbound methods change significantly in Python 3. For instance: class SomeObject(object):
 def method():
 pass In Python 2: - Unbound method inspect.ismethod(SomeObject.method) returns True - Unbound inspect.isfunction(SomeObject.method) returns False - Unbound hasattr(SomeObject.method, 'im_class') returns True - Bound method inspect.ismethod(SomeObject().method) returns True - Bound method inspect.isfunction(SomeObject().method) returns False - Bound hasattr(SomeObject().method, 'im_class') returns True In Python 3: - Unbound method inspect.ismethod(SomeObject.method) returns False - Unbound inspect.isfunction(SomeObject.method) returns True - Unbound hasattr(SomeObject.method, 'im_class') returns False - Bound method inspect.ismethod(SomeObject().method) returns True - Bound method inspect.isfunction(SomeObject().method) returns False - Bound hasattr(SomeObject().method, 'im_class') returns False This method tries to consolidate the approach for retrieving the enclosing type of a bound/unbound method and functions. """

    thing = target_thing
    if hasattr(thing, 'im_class'):
        # only works in Python 2
        return thing.im_class.__name__
    if inspect.ismethod(thing):
        for cls in inspect.getmro(thing.__self__.__class__):
            if cls.__dict__.get(thing.__name__) is thing:
                return cls.__name__
        thing = thing.__func__
    if inspect.isfunction(thing) and hasattr(thing, '__qualname__'):
        qualifier = thing.__qualname__
        if LOCALS_TOKEN in qualifier:
            return _get_local_type_name(thing)
        return _get_external_type_name(thing)
    return inspect.getmodule(target_thing).__name__