Stack Exchange
Canonical way to check `bpy` object subtype — `.type` attribute vs. `isinstance()`?
Two ways are available to check the subtypes of many Blender/bpy object types.
isinstance() works with types exposed in bpy.types:
>>> isinstance(C.object.modifiers[0], bpy.types.NodesModifier)
True

Many bpy types also expose a property like .type:
>>> C.object.modifiers[0].type == 'NODES'
True

Is there an official recommendation for which of these techniques should be preferred? Are there practical advantages or drawbacks to each?

there is also type(C.object.modifiers[0] == bpy.types.NodesModifier) and C.object.modifiers[0].__class__ == bpy.types.NodesModifier

I think isinstance is preferred to testing type(obj) and obj.__class__ because it takes inheritance into account. See https://stackoverflow.com/a/1549854/7092409 for a detailed answer. Also, single and double underscore members and methods should generally not be accessed from outside the class definition.
obj.type is an abstraction layer that doesn't depend on the API implementation. It is more robust because if the implementation changes in the future (for example if the class name changes), this member can still point to the same value. However, it is more fragile because it depends on a subjective string value, which can be misspelled, mis-copy/pasted, mis-translated, etc.
Note that the linked answer suggests that none of these methods should generally be used. The other (more pythonic ?) solution is to treat your data as if it was of the type you want it to be, and catch any exception in a try: ... except TypeError: block. Ask not for permission but for forgiveness.
