11

Code:

import types


class C(object):
    pass


c = C()
print(isinstance(c, types.InstanceType))

Output:

False

What correct way to check if object is instance of user-defined class for new-style classes?

UPD:

I want put additional emphasize on if checking if type of object is user-defined. According to docs:

types.InstanceType
The type of instances of user-defined classes.

UPD2:

Alright - not "correct" ways are OK too.

UPD3:

Also noticed that there is no type for set in module types

m.brindley
  • 1,218
  • 10
  • 19
Gill Bates
  • 14,330
  • 23
  • 70
  • 138

4 Answers4

9

You can combine the x.__class__ check with the presence (or not) of either '__dict__' in dir(x) or hasattr(x, '__slots__'), as a hacky way to distinguish between both new/old-style class and user/builtin object.

Actually, this exact same suggestions appears in https://stackoverflow.com/a/2654806/1832154

def is_instance_userdefined_and_newclass(inst):
    cls = inst.__class__
    if hasattr(cls, '__class__'):
        return ('__dict__' in dir(cls) or hasattr(cls, '__slots__'))
    return False

>>> class A: pass
... 
>>> class B(object): pass
... 
>>> a = A()
>>> b = B()
>>> is_instance_userdefined_and_newclass(1)
False
>>> is_instance_userdefined_and_newclass(a)
False
>>> is_instance_userdefined_and_newclass(b)
True
Community
  • 1
  • 1
mmgp
  • 18,901
  • 3
  • 53
  • 80
  • Except that that will fail with objects defined in a c library. I guess the term hackish is appropriate. – Antimony Feb 02 '13 at 00:47
  • @Antimony do you typically create (i.e. code) a class in a C library and load it while running a python code ? By user-defined I simply took that the user created it purely using Python, without relying on the CPython API with C code. And I'm aware this method can fail, but there is nothing else that works for the given question (your answer doesn't). – mmgp Feb 02 '13 at 00:50
  • @mmgp Seems like this is the answer, thank you! I will wait 4 days more and accept/award your answer if no less hackish solutions will be posted. – Gill Bates Feb 03 '13 at 23:40
  • **Brilliant.** I needed this today for precisely the same reason Gill needed this three years ago: [memory profiling](https://stackoverflow.com/questions/14612865/how-to-check-if-object-is-instance-of-new-style-user-defined-class#comment20486559_14612865). When recursively profiling the space consumed by _user-defined_ objects and the complete tree of _user-defined_ referents those objects transitively refer to, recursion naturally bottoms out at _built-in_ objects. This simple (albeit hackish) test just saved my Canadian bacon. – Cecil Curry Dec 07 '16 at 05:14
  • Relatedly, the last three lines of `is_instance_userdefined_and_newclass()` reduce to a single statement: `return hasattr(cls, '__class__') and ('__dict__' in dir(cls) or hasattr(cls, '__slots__'))`. Negligible efficiency gains for the win. – Cecil Curry Dec 07 '16 at 05:19
  • See also [this related answer](https://stackoverflow.com/a/41012823/2809027), generalizing the above answer to reliably detect both pure-Python classes _and_ class instances in a Python 3.x-specific manner – complete with wild and/or crazy CPython optimization. – Cecil Curry Dec 07 '16 at 08:46
7

I'm not sure about the "correct" way, but one easy way to test it is that instances of old style classes have the type 'instance' instead of their actual class.

So type(x) is x.__class__ or type(x) is not types.InstanceType should both work.

>>> class Old:
...     pass
...
>>> class New(object):
...     pass
...
>>> x = Old()
>>> y = New()
>>> type(x) is x.__class__
False
>>> type(y) is y.__class__
True
>>> type(x) is types.InstanceType
True
>>> type(y) is types.InstanceType
False
Antimony
  • 37,781
  • 10
  • 100
  • 107
  • Beat me to it. I'll add the link in your answer, if you don't mind – loopbackbee Jan 30 '13 at 20:23
  • Feel free to add the link. – Antimony Jan 30 '13 at 20:23
  • Actually `type(x) is x.__class__` returns `True` even if `x = 1`. So this way is not similar to `isinstance(x, types.InstanceType)` – Gill Bates Jan 30 '13 at 20:25
  • I can't edit your question yet, but [here's the relevant question with more information about this](http://stackoverflow.com/questions/54867/) – loopbackbee Jan 30 '13 at 20:26
  • @Gill that's because `int` is a new style class. Based on your actual edited question, it looks like you're out of luck. – Antimony Jan 30 '13 at 23:53
  • @Antimony question initially was about user-defined classes, in edits I just highlighted this. – Gill Bates Jan 31 '13 at 10:01
  • @Gill well it depends on what you mean by a 'user defined' type, but I don't think there's any easy or reliable way to do want you want. The whole point is that the builtin types aren't any different than what you can create. – Antimony Jan 31 '13 at 13:45
  • @Antimony I think of user-defined classes as about complex classes that built on basic classes such as int/str/float etc. – Gill Bates Jan 31 '13 at 14:05
  • @Gill but there's no difference between them. At best you can hack something together using a manual list of builtin types or using `inspect` to try to find out where the class was defined, but it's ugly and unreliable. – Antimony Jan 31 '13 at 15:08
  • @Antimony There is a difference - how can you build your own class, without using basic types? You cant operate with ones and zeroes in memory, and you must rely to basic types - that's my point. – Gill Bates Jan 31 '13 at 16:35
  • @Gill the builtin types don't "operate on ones or zeroes" either. In the particular case of CPython, they're wrappers around C code, but you can just as easily define your own types based on C code. – Antimony Jan 31 '13 at 17:35
  • @Antimony How can you say that Python objects are the same as types, if at the same time you say that, you need to dive into lower-level code of particular implementation of language to define types. Alright - they "unified" in Python, but that's doesnt mean that they are same, that gives to programmer ability to inherit basic types in Python - that is one of the goals of unification. Purpose of "types" is human-friendly interpretation binary data. Purpose of objects is to organize code using OO approach. – Gill Bates Jan 31 '13 at 21:45
1

This tells us True if it is.

if issubclass(checkthis, (object)) and 'a' not in vars(__builtins__):print"YES!"

The second argument is a tuple of the classes to be checked. This is easy to understand and i'm sure it works. [edit (object) to(object,) thanks Duncan!]

noɥʇʎԀʎzɐɹƆ
  • 9,967
  • 2
  • 50
  • 67
  • 1
    Your second argument is simply `object`. The parentheses don't magically turn it into a tuple: commas make tuples so `(object,)` would be a one element tuple. However in this case passing just `object` works fine because the second argument of `issubclass()` can be either a class or a tuple of things that `issubclass()` takes as its second argument. (Yes, the definition is recursive so you can use nested tuples of classes.) – Duncan Feb 06 '13 at 13:33
  • 1
    `issubclass(int, (object,))` also returns `True` and so doesn't do what the OP asked for. – Ethan Furman Feb 07 '13 at 20:22
  • Actually, the OP said 'not "correct" answers', which I understood to mean something that works even if it's not an official way. But I can see the confusion: downvote removed. – Ethan Furman Feb 08 '13 at 02:27
0

Probably I can go with elimination method - not checking if object is instance of user-defined class explicitly - isinstance(object, RightTypeAliasForThisCase), but checking if object not one of 'basic' types.

Gill Bates
  • 14,330
  • 23
  • 70
  • 138