class a:
pass
class b(a):
pass
c = b()
type(c) == a #returns False
Is there an alternative to type() that can check if an object inherits from a class?
Yes, isinstance: isinstance(obj, Klass)
isinstance and issubclass are applicable if you know what to check against. If you don't know, and if you actually want to list the base types, there exist the special attributes __bases__ and __mro__ to list them:
To list the immediate base classes, consider class.__bases__. For example:
>>> from pathlib import Path
>>> Path.__bases__
(<class 'pathlib.PurePath'>,)
To effectively recursively list all base classes, consider class.__mro__ or class.mro():
>>> from pathlib import Path
>>> Path.__mro__
(<class 'pathlib.Path'>, <class 'pathlib.PurePath'>, <class 'object'>)
>>> Path.mro()
[<class 'pathlib.Path'>, <class 'pathlib.PurePath'>, <class 'object'>]
>>> class a:
... pass
...
>>> class b(a):
... pass
...
>>> c = b()
>>> d = a()
>>> type(c) == type(d)
True
type() returns a type object. a is the actual class, not the type
Related
Im trying to compare types of two objects by using isinstance(obj1, type(obj2)).
However, im not really sure how type infers the typing of an object - or whether theres a chance that the type returned is of an ancestor class.
Given three classes A, B, C. Class B is subclass of A and class C is subclass of B.
class A:
pass
class B(A):
pass
class C(B):
pass
Using type on an object is the same thing as calling obj.__class__. This returns the class to which an instance belongs.
isinstance however also checks for subclasses. So your call isinstance(obj1, type(obj2)) depends on if the two objects are related.
>>> a = A()
>>> b = B()
>>> c = C()
>>> type(c) == type(b)
False
>>> isinstance(c, type(b))
True
Instance c is of type <class '__main__.C'> and b is of type <class '__main__.B'>. So the comparison using type evaluates to False.
A more elaborate example of your approach and using the class directly:
>>> isinstance(c, type(b)) # as C is subclass of B
True
>>> isinstance(c, B) # using the class directly
True
>>> isinstance(b, type(c)) # as b is of parent class B
False
>>> isinstance(b, C) # C is subclass of B, thus b is not an instance of C
False
>>> isinstance(c, type(a)) # C is subclass of B which is subclass of A
True
In python, if class C inherits from two other classes C(A,B), and A and B have methods with identical names but different return values, which value will that method return on C?
"Inherits two methods" isn't quite accurate. What happens is that C has a method resolution order (MRO), which is the list [C, A, B, object]. If you attempt to access a method that C does not define or override, the MRO determines which class will be checked next. If the desired method is defined in A, it shadows a method with the same name in B.
>>> class A:
... def foo(self):
... print("In A.foo")
...
>>> class B:
... def foo(self):
... print("In B.foo")
...
>>> class C(A, B):
... pass
...
>>> C.mro()
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
>>> C().foo()
In A.foo
MRO order will be followed now, if you inherit A and B in C, then preference order goes from left to right, so, A will be prefered and method of A will be called instead of B
Consider the following case:
>>> "a".capitalize.__call__
<method-wrapper '__call__' of builtin_function_or_method object at 0x1022e70d8>
>>> "a".capitalize.__call__.__call__
<method-wrapper '__call__' of method-wrapper object at 0x1022e2b70>
>>> id("a".capitalize.__call__)
4331547448
>>> id("a".capitalize.__call__.__call__)
4331547504
>>> id("a".capitalize.__call__) == id("a".capitalize.__call__.__call__)
False
How can I establish at runtime that the __call__ refers to the same base symbol in both cases ?
Edit:
It is possible that expecting something like this to exist for __call__ in the first place is unreasonable because __call__ might not have a base symbol that is not bound to any object - in which case what is the best way to detect that other than keeping a list of special names (how can such a list be built authoritatively ?) ?
Won't work for builtin_function_or_method as they have no __func__.
If you're only working with your classes you can compare __func__:
>>> class Foo:
... def bar(self):
... pass
...
>>>
>>> a = Foo()
>>> b = Foo()
>>> a.bar.__func__
<function Foo.bar at 0x7f6f103e5ae8>
>>> a.bar.__func__ is b.bar.__func__
True
But I'd say it's better to do it the other way around: instead of trying to get the function from the instance, get up to the type first:
type(a).bar is type(a).bar
Which should work even for bltns:
>>> type("").capitalize is type("a").capitalize
True
And for hierarchies:
>>> class A:
... def foo(self):...
...
>>> class B(A):...
...
>>> a = A()
>>> b = B()
>>> type(a).foo is type(b).foo
True
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
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
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
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!]
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.
>>> import sys
>>> sys.version_info
(2, 4, 4, 'final', 0)
>>> class C:
... pass
...
>>> issubclass(C, C)
True
>>> issubclass(C, object)
False
>>> class T(object):
... pass
...
>>> issubclass(T, T)
True
>>> issubclass(T, object)
True
>>>
Question 1> Why C is a subclass of C?
Question 2> what is the base class of C?
Thank you
// Update for Chris Morgan (At least for me, the following manual doesn't help at all)
>>> help(issubclass)
Help on built-in function issubclass in module __builtin__:
issubclass(...)
issubclass(C, B) -> bool
Return whether class C is a subclass (i.e., a derived class) of class B.
When using a tuple as the second argument issubclass(X, (A, B, ...)),
is a shortcut for issubclass(X, A) or issubclass(X, B) or ... (etc.).
Take a look at issubclass(class, classinfo) documentation
Return true if class is a subclass (direct, indirect or virtual) of
classinfo. A class is considered a subclass of itself. classinfo may
be a tuple of class objects, in which case every entry in classinfo
will be checked. In any other case, a TypeError exception is raised.
and to check base class of C use inspect.getmro(cls) function.
Return a tuple of class cls’s base classes, including cls, in method
resolution order.
>>> class C(object):
... pass
...
>>> inspect.getmro(C)
(<class '__main__.C'>, <type 'object'>)
>>>
http://docs.python.org/library/functions.html#issubclass From that link, "A class is considered a subclass of itself."
To answer your second question, C is an "old style" class so it isn't a subclass of object. Include object as the superclass if you want a new style class. See http://www.python.org/doc/newstyle/ for more info.
http://docs.python.org/library/functions.html#issubclass
A class is considered a subclass of itself.
C has no base class
print C.__bases__
()