2

I have a library module-wrapper that recursively wraps objects. I want to determine if an object has a function-like type. I can check almost all function-like object using:

inspect.isbuiltin(object=obj) or
inspect.isfunction(object=obj) or
inspect.ismethod(object=obj) or
inspect.ismethoddescriptor(object=obj)

The problem is that some bound methods are not detected with this code, for example:

s = "Hello, world!"
type(s.__add__)
# method-wrapper

I guess I cannot check objects for being method-wrapper using inspect module. But how do I import this type? I didn't find it.

Now I have an ugly hack in my code:

MethodWrapper = type(''.__add__)
isinstance(obj, MethodWrapper)

UPD0:

I don't want to use callable because it detects classes and objects, that implement __call__, but I want those classes and objects to be handled separately.

rominf
  • 2,719
  • 3
  • 21
  • 39

1 Answers1

1

The types module provides names for many “implementation” types, including several for functions implemented in C. The specific example of type("".__str__), MethodWrapperType, was just added in CPython 3.7.

Because this area is subtle and the number of types is large, callable may really be the best choice. You can easily check for type objects first to “exclude” classes, and various heuristics (e.g., trying to call vars on an object or examining type(x).__module__) can be used to recognize typical “callable objects” (not that those are fundamentally different from the built-in function types).

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • I didn't find anything in the `types` module. I don't want to use `callable` because it detects classes and objects, that implement `__call__`, but I want those classes and objects to be handled separately. – rominf Nov 03 '18 at 13:48
  • 1
    It [seems](https://wandbox.org/permlink/ROJ5hVWHhtbYSY21) to handle your `"".__add__` case just fine (but that name was added only in 3.7). If you want to treat classes differently, just check for them first; `vars` might help with the mostly-arbitrary distinction between "raw functions" and "user-level callable objects". – Davis Herring Nov 03 '18 at 14:23
  • Davis, can you please edit your answer so that I could upvote it (I downvoted it because I didn't find anything in the `types` module of Python 3.6). – rominf Nov 03 '18 at 17:09
  • 1
    @rominf: Integrating the comments is a good idea and has been done—not that anything forced you to downvote at the *same time* as asking about an apparent inconsistency (and editing your question). – Davis Herring Nov 03 '18 at 17:32
  • Davis sorry, I didn't get the point about callable objects. Can you elaborate? – rominf Nov 03 '18 at 18:53
  • Davis, by some reason if I use `@` to mention you I get nothing in the output instead of mentioning you. It's strange. I think it's SO bug. – rominf Nov 03 '18 at 18:55
  • 1
    @rominf: As it’s my answer, I get notified regardless; I think it strips the mention for brevity. – Davis Herring Nov 03 '18 at 19:01
  • @rominf: It’s something of a philosophical question as yo whether an object that provides `__call__` *is* a function or merely *acts* like one. It’s even possible to have an object of a `class` type that invokes a C-defined function when called (with **no** `def __call__(self):` intermediary). – Davis Herring Nov 03 '18 at 19:04