How to check if object is instance of new-style user-defined class?
Asked Answered
P

4

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

Papiamento answered 30/1, 2013 at 20:16 Comment(4)
This is an odd need, what is it for?Constituency
Im trying to write a simple function to measure how much memory takes object provided as argumentPapiamento
Hmm, I still don't understand. Why do you need to know if it's a user-defined class? What will you do in the yes case that's different than the no case?Constituency
@NedBatchelder Probably it was __slots__ issue or something like that.Papiamento
O
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://mcmap.net/q/835389/-identifying-that-a-variable-is-a-new-style-class-in-python

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
Operon answered 1/2, 2013 at 20:40 Comment(6)
Except that that will fail with objects defined in a c library. I guess the term hackish is appropriate.Exhaustless
@Exhaustless 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).Operon
@Operon 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.Papiamento
Brilliant. I needed this today for precisely the same reason Gill needed this three years ago: memory profiling. 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.Hiphuggers
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.Hiphuggers
See also this related answer, 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.Hiphuggers
E
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
Exhaustless answered 30/1, 2013 at 20:20 Comment(12)
Beat me to it. I'll add the link in your answer, if you don't mindKantian
Feel free to add the link.Exhaustless
Actually type(x) is x.__class__ returns True even if x = 1. So this way is not similar to isinstance(x, types.InstanceType)Papiamento
I can't edit your question yet, but here's the relevant question with more information about thisKantian
@Gill that's because int is a new style class. Based on your actual edited question, it looks like you're out of luck.Exhaustless
@Exhaustless question initially was about user-defined classes, in edits I just highlighted this.Papiamento
@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.Exhaustless
@Exhaustless I think of user-defined classes as about complex classes that built on basic classes such as int/str/float etc.Papiamento
@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.Exhaustless
@Exhaustless 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.Papiamento
@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.Exhaustless
@Exhaustless 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.Papiamento
T
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!]

Tsui answered 2/2, 2013 at 16:23 Comment(3)
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.)Mentalist
issubclass(int, (object,)) also returns True and so doesn't do what the OP asked for.Vaginitis
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.Vaginitis
P
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.

Papiamento answered 30/1, 2013 at 21:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.