Python type() or __class__, == or is

前端 未结 4 601
萌比男神i
萌比男神i 2020-12-13 03:41

I want to test whether an object is an instance of a class, and only this class (no subclasses). I could do it either with:

obj.__class__ == Foo
obj.__class_         


        
相关标签:
4条回答
  • 2020-12-13 04:02

    The result of type() is equivalent to obj.__class__ in new style classes, and class objects are not safe for comparison using is, use == instead.

    For new style classes the preferable way here would be type(obj) == Foo.

    As Michael Hoffman pointed out in his answer, there is a difference here between new and old style classes, so for backwards compatible code you may need to use obj.__class__ == Foo.

    For those claiming that isinstance(obj, Foo) is preferable, consider the following scenario:

    class Foo(object):
        pass
    
    class Bar(Foo):
        pass
    
    >>> obj = Bar()
    >>> isinstance(obj, Foo)
    True
    >>> type(obj) == Foo
    False
    

    The OP wants the behavior of type(obj) == Foo, where it will be false even though Foo is a base class of Bar.

    0 讨论(0)
  • 2020-12-13 04:02

    Update: Thanks all for the feedback. I'm still puzzled by whether or not class objects are singletons, my common sense says they are, but it's been really hard to get a confirmation (try googling for "python", "class" and "unique" or "singleton").

    I can confirm that __instance__ is a singleton. Here is the proof.

    >>> t1=File.test()
    made class
    >>> t2=File.test()
    made class
    >>> print t1.__class__()
    made class
    <File.test object at 0x1101bdd10>
    >>> print t2.__class__()
    made class
    <File.test object at 0x1101bdd10>
    

    As you can see both t1 and t2 print out the same value in memory even though t1 and t2 are at different values in memory. Here is the proof of that.

    >>> print t1
    <File.test object at 0x1101bdc90>
    >>> print t2
    <File.test object at 0x1101bdcd0>
    

    The __instance__ method only exists if you used class "name"(object):. If you use the classic style class, class "name":, than the __instance__ method doesn't exist.

    What this means is to be the most generic you probably want to use type unless you know for a fact instance does exist.

    0 讨论(0)
  • 2020-12-13 04:17

    For old-style classes, there is a difference:

    >>> class X: pass
    ... 
    >>> type(X)
    <type 'classobj'>
    >>> X.__class__
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: class X has no attribute '__class__'
    >>> x = X()
    >>> x.__class__
    <class __main__.X at 0x171b5d50>
    >>> type(x)
    <type 'instance'>
    

    The point of new-style classes was to unify class and type. Technically speaking, __class__ is the only solution that will work both for new and old-style class instances, but it will also throw an exception on old-style class objects themselves. You can call type() on any object, but not every object has __class__. Also, you can muck with __class__ in a way you can't muck with type().

    >>> class Z(object):
    ...     def __getattribute__(self, name):
    ...             return "ham"
    ... 
    >>> z = Z()
    >>> z.__class__
    'ham'
    >>> type(z)
    <class '__main__.Z'>
    

    Personally, I usually have an environment with new-style classes only, and as a matter of style prefer to use type() as I generally prefer built-in functions when they exist to using magic attributes. For example, I would also prefer bool(x) to x.__nonzero__().

    0 讨论(0)
  • 2020-12-13 04:26

    is should only be used for identity checks, not type checks (there is an exception to the rule where you can and should use is for check against singletons).

    Note: I would generally not use type and == for type checks, either. The preferable way for type checks is isinstance(obj, Foo). If you ever have a reason to check if something is not an subclass instance, it smells like a fishy design to me. When class Foo(Bar):, then Bar is a Foo, and you should be avoiding any situations where some part of your code has to work on a Foo instance but breaks on a Bar instance.

    0 讨论(0)
提交回复
热议问题