def has_method(obj, name):
    if (not hasattr(obj, name)):
        return False
    func = getattr(obj, name)
    if isinstance(func, types.BuiltinMethodType):
        return True
    if (not isinstance(func, (types.MethodType, types.FunctionType))):
        return False
    base_type = (obj if is_type(obj) else obj.__class__)
    original = None
    for subtype in inspect.getmro(base_type):
        original = vars(subtype).get(name)
        if (original is not None):
            break
    if (original is None):
        return False
    if isinstance(original, staticmethod):
        return True
    self_attr = ('__self__' if PY3 else 'im_self')
    if (not hasattr(func, self_attr)):
        return False
    bound_to = getattr(func, self_attr)
    if isinstance(original, classmethod):
        return issubclass(base_type, bound_to)
    return isinstance(obj, type(bound_to))
def has_method(obj, name):
    if (not hasattr(obj, name)):
        return False
    func = getattr(obj, name)
    if isinstance(func, types.BuiltinMethodType):
        return True
    if (not isinstance(func, (types.MethodType, types.FunctionType))):
        return False
    base_type = (obj if is_type(obj) else obj.__class__)
    original = None
    for subtype in inspect.getmro(base_type):
        original = vars(subtype).get(name)
        if (original is not None):
            break
    if (original is None):
        return False
    if isinstance(original, staticmethod):
        return True
    self_attr = ('__self__' if PY3 else 'im_self')
    if (not hasattr(func, self_attr)):
        return False
    bound_to = getattr(func, self_attr)
    if isinstance(original, classmethod):
        return issubclass(base_type, bound_to)
    return isinstance(obj, type(bound_to))