As others have answered, there could be other numeric types besides the ones you mention.
One approach would be to check explicitly for the capabilities you want, with something like
attrs = ['__add__', '__sub__', '__mul__', '__div__', '__pow__']
return all(hasattr(obj, attr) for attr in attrs)
This works for all your examples except the last one,
numpy.array(['1']). That's because
numpy.ndarray has the special methods for numeric operations but raises TypeError if you try to use them inappropriately with string or object arrays. You could add an explicit check for this like
... and not (isinstance(obj, ndarray) and obj.dtype.kind in 'OSU')
This may be good enough.
But... you can never be 100% sure that somebody won't define another type with the same behavior, so a more foolproof way is to actually try to do a calculation and catch the exception, something like
obj+obj, obj-obj, obj*obj, obj**obj, obj/obj
but depending on how often you plan to call use it and with what arguments, this may not be practical (it can be potentially slow, e.g. with large arrays).