Inheritance and isinstance - python

I just noticed that
isinstance(myob, MyClass)
does not only return True when myob is an instance of MyClass but also if myob is an instance of a class that inherits from MyClass.
To be more clear, consider the following:
class Book(object):
def __init__(self, cover)
self._cover = cover
class Novel(Book):
def __init__(self, cover, category):
Book.__init__(self, cover)
self._category = category
When instanciating Novel as follows:
novel = Novel('hardcover', 'police')
then
print(isinstance(novel, Book))
and
print (isinstance(novel , Novel))
both print True.
Why is that so? In my sense, novel is a Novel instance, not a Book one...
Also, relevant to this :
In order to get the "grand-mother" (sic) class, I do:
print(novel.__class__.__bases__)
Is there a more direct way?

This transitive behavior is how it should work intuitively ...
>>> class Text:
...: pass
...:
...:
>>> class Book(Text):
...: pass
...:
...:
>>> class Novel(Book):
...: pass
...:
...:
>>> n = Novel()
>>> isinstance(n, Novel)
>>> True
>>> isinstance(n, Book)
>>> True
>>> isinstance(n, Text)
>>> True
... because a Novel is-a Novel, but also is-a Book and is-a Text.
If you want to know whether a class (or instance of a class) is a direct ancestor of another class, you can use the __subclasses__ method of class objects.
>>> Text.__subclasses__()
>>> [__main__.Book]
>>> Book.__subclasses__()
>>> [__main__.Novel]
>>> Novel.__subclasses__()
>>> []
>>>
>>> Novel in Text.__subclasses__()
>>> False
>>> type(n) in Text.__subclasses__()
>>> False
>>> Novel in Book.__subclasses__()
>>> True
>>> type(n) in Book.__subclasses__()
>>> True
edit: YourClass.__bases__ also gives you all direct parent classes.
>>> Novel.__bases__
>>> (__main__.Book,)

Inheritance is "is a" relationship - if Duck inherit from Bird then obviously a duck (instance of Duck) is ALSO a bird (instance of Bird), so the behaviour you observe is really the expected one (and this holds for all class-based OOPLs).
If you want to check the exact type of an object, you can get it using type(obj) - which will return the class of object - and do an identity test against the desired class, ie:
obj = 42
print(type(obj) is int)

Related

How do we get an optional class attribute in Python?

For dictionary we can use .get method. What about a class's attribute and provide a default value?
You can use hasattr and getattr.
For example:
hasattr(foo, 'bar')
would return True if foo has an attribute named bar, otherwise False and
getattr(foo, 'bar', 'quux')
would return foo.bar if it exists, otherwise defaults to quux.
It's dead simple: use a keyword argument.
>>> class Foo(object):
... def __init__(self, my_foo=None):
... self.my_foo = my_foo
...
>>> f = Foo()
>>> f.my_foo
>>> repr(f.my_foo)
'None'
>>> f2 = Foo(2)
>>> f2.my_foo
2
If you are looking for an object which does not have an attribute until you set it, Jason's idea is pretty good unless you directly refer to the attribute. You'll have to work around the AttributeError you'll get. Personally, I'm not a fan of creating objects which must be constantly surrounded by try/except blocks just for the sake of not setting an instance attribute.
Python isn't much for getters and setters. However, you can use property() to work around this problem:
>>> class Foo(object):
... def __init__(self):
... pass
... def get_my_foo(self):
... return getattr(self, "_my_foo", "there's no my_foo")
... def set_my_foo(self, foo):
... self._my_foo = foo
... my_foo = property(get_my_foo, set_my_foo)
...
>>> f = Foo()
>>> f.my_foo
"there's no my_foo"
>>> f.my_foo = "foo!"
>>> f.my_foo
'foo!'
It works just as well to call get_my_foo and set_my_foo, if you like. An added benefit is that you can omit the setter to make a read-only attribute, provided someone using your object doesn't change the underlying _my_foo.

Python class returning value

I'm trying to create a class that returns a value, not self.
I will show you an example comparing with a list:
>>> l = list()
>>> print(l)
[]
>>> class MyClass:
>>> pass
>>> mc = MyClass()
>>> print mc
<__main__.MyClass instance at 0x02892508>
I need that MyClass returns a list, like list() does, not the instance info. I know that I can make a subclass of list. But is there a way to do it without subclassing?
I want to imitate a list (or other objects):
>>> l1 = list()
>>> l2 = list()
>>> l1
[]
>>> l2
[]
>>> l1 == l2
True
>>> class MyClass():
def __repr__(self):
return '[]'
>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1
[]
>>> m2
[]
>>> m1 == m2
False
Why is m1 == m2 False? This is the question.
I'm sorry if I don't respond to all of you. I'm trying all the solutions you give me. I cant use def, because I need to use functions like setitem, getitem, etc.
I think you are very confused about what is occurring.
In Python, everything is an object:
[] (a list) is an object
'abcde' (a string) is an object
1 (an integer) is an object
MyClass() (an instance) is an object
MyClass (a class) is also an object
list (a type--much like a class) is also an object
They are all "values" in the sense that they are a thing and not a name which refers to a thing. (Variables are names which refer to values.) A value is not something different from an object in Python.
When you call a class object (like MyClass() or list()), it returns an instance of that class. (list is really a type and not a class, but I am simplifying a bit here.)
When you print an object (i.e. get a string representation of an object), that object's __str__ or __repr__ magic method is called and the returned value printed.
For example:
>>> class MyClass(object):
... def __str__(self):
... return "MyClass([])"
... def __repr__(self):
... return "I am an instance of MyClass at address "+hex(id(self))
...
>>> m = MyClass()
>>> print m
MyClass([])
>>> m
I am an instance of MyClass at address 0x108ed5a10
>>>
So what you are asking for, "I need that MyClass return a list, like list(), not the instance info," does not make any sense. list() returns a list instance. MyClass() returns a MyClass instance. If you want a list instance, just get a list instance. If the issue instead is what do these objects look like when you print them or look at them in the console, then create a __str__ and __repr__ method which represents them as you want them to be represented.
Update for new question about equality
Once again, __str__ and __repr__ are only for printing, and do not affect the object in any other way. Just because two objects have the same __repr__ value does not mean they are equal!
MyClass() != MyClass() because your class does not define how these would be equal, so it falls back to the default behavior (of the object type), which is that objects are only equal to themselves:
>>> m = MyClass()
>>> m1 = m
>>> m2 = m
>>> m1 == m2
True
>>> m3 = MyClass()
>>> m1 == m3
False
If you want to change this, use one of the comparison magic methods
For example, you can have an object that is equal to everything:
>>> class MyClass(object):
... def __eq__(self, other):
... return True
...
>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1 == m2
True
>>> m1 == m1
True
>>> m1 == 1
True
>>> m1 == None
True
>>> m1 == []
True
I think you should do two things:
Take a look at this guide to magic method use in Python.
Justify why you are not subclassing list if what you want is very list-like. If subclassing is not appropriate, you can delegate to a wrapped list instance instead:
class MyClass(object):
def __init__(self):
self._list = []
def __getattr__(self, name):
return getattr(self._list, name)
# __repr__ and __str__ methods are automatically created
# for every class, so if we want to delegate these we must
# do so explicitly
def __repr__(self):
return "MyClass(%s)" % repr(self._list)
def __str__(self):
return "MyClass(%s)" % str(self._list)
This will now act like a list without being a list (i.e., without subclassing list).
>>> c = MyClass()
>>> c.append(1)
>>> c
MyClass([1])
If what you want is a way to turn your class into kind of a list without subclassing list, then just make a method that returns a list:
def MyClass():
def __init__(self):
self.value1 = 1
self.value2 = 2
def get_list(self):
return [self.value1, self.value2...]
>>>print MyClass().get_list()
[1, 2...]
If you meant that print MyClass() will print a list, just override __repr__:
class MyClass():
def __init__(self):
self.value1 = 1
self.value2 = 2
def __repr__(self):
return repr([self.value1, self.value2])
EDIT:
I see you meant how to make objects compare. For that, you override the __cmp__ method.
class MyClass():
def __cmp__(self, other):
return cmp(self.get_list(), other.get_list())
Use __new__ to return value from a class.
As others suggest __repr__,__str__ or even __init__ (somehow) CAN give you what you want, But __new__ will be a semantically better solution for your purpose since you want the actual object to be returned and not just the string representation of it.
Read this answer for more insights into __str__ and __repr__
https://stackoverflow.com/a/19331543/4985585
class MyClass():
def __new__(cls):
return list() #or anything you want
>>> MyClass()
[] #Returns a true list not a repr or string
class MyClass():
def __init__(self, a, b):
self.value1 = a
self.value2 = b
def __call__(self):
return [self.value1, self.value2]
Testing:
>>> x = MyClass('foo','bar')
>>> x()
['foo', 'bar']
You are describing a function, not a class.
def Myclass():
return []
the worked proposition for me is __call__ on class who create list of little numbers:
import itertools
class SmallNumbers:
def __init__(self, how_much):
self.how_much = int(how_much)
self.work_list = ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
self.generated_list = ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
start = 10
end = 100
for cmb in range(2, len(str(self.how_much)) + 1):
self.ListOfCombinations(is_upper_then=start, is_under_then=end, combinations=cmb)
start *= 10
end *= 10
def __call__(self, number, *args, **kwargs):
return self.generated_list[number]
def ListOfCombinations(self, is_upper_then, is_under_then, combinations):
multi_work_list = eval(str('self.work_list,') * combinations)
nbr = 0
for subset in itertools.product(*multi_work_list):
if is_upper_then <= nbr < is_under_then:
self.generated_list.append(''.join(subset))
if self.how_much == nbr:
break
nbr += 1
and to run it:
if __name__ == '__main__':
sm = SmallNumbers(56)
print(sm.generated_list)
print(sm.generated_list[34], sm.generated_list[27], sm.generated_list[10])
print('The Best', sm(15), sm(55), sm(49), sm(0))
result
['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉', '₁₀', '₁₁', '₁₂', '₁₃', '₁₄', '₁₅', '₁₆', '₁₇', '₁₈', '₁₉', '₂₀', '₂₁', '₂₂', '₂₃', '₂₄', '₂₅', '₂₆', '₂₇', '₂₈', '₂₉', '₃₀', '₃₁', '₃₂', '₃₃', '₃₄', '₃₅', '₃₆', '₃₇', '₃₈', '₃₉', '₄₀', '₄₁', '₄₂', '₄₃', '₄₄', '₄₅', '₄₆', '₄₇', '₄₈', '₄₉', '₅₀', '₅₁', '₅₂', '₅₃', '₅₄', '₅₅', '₅₆']
₃₄ ₂₇ ₁₀
The Best ₁₅ ₅₅ ₄₉ ₀

Is there a way to identify an inherited method in Python?

I want to tell inherited methods apart from overloaded or newly defined methods. Is that possible with Python?
Example:
class A(object):
def spam(self):
print 'A spam'
def ham(self):
print 'A ham'
class B(A):
def spam(self):
print 'Overloaded spam'
def eggs(self):
print 'Newly defined eggs'
Desired functionality:
>>> magicmethod(B.spam)
'overloaded'
>>> magicmethod(B.ham)
'inherited'
>>> magicmethod(B.eggs)
'newly defined'
Is there a "magic method" like in the example, or some way to tell those types of method implementations apart?
I'm not sure it's a good idea, but you can probably do it by using hasattr and __dict__.
def magicmethod(clazz, method):
if method not in clazz.__dict__: # Not defined in clazz : inherited
return 'inherited'
elif hasattr(super(clazz), method): # Present in parent : overloaded
return 'overloaded'
else: # Not present in parent : newly defined
return 'newly defined'
If you know the ancestor, you can simply test:
>>> B.spam == A.spam
False
>>> B.ham == A.ham
True
And to find list of all base classes, look here: List all base classes in a hierarchy of given class?
I shall also point that if you need this, your class design is probably wrong. You should not care about such things in OOP (unless you're creating an object inspector or something like that).
A general way will be (python 2.*):
def _getclass(method):
try:
return method.im_class
except AttributeError:
return method.__class__
def magicmethod(method):
method_cls = _getclass(method)
if method.__name__ not in method_cls.__dict__:
return 'inherited'
for cls in method_cls.__mro__[1:]:
if method.__name__ in cls.__dict__:
return 'overloaded'
return 'newly defined'
__test__ = {"example": """
>>> class A(object):
... def spam(self):
... print 'A spam'
... def ham(self):
... print 'A ham'
>>> class B(A):
... def spam(self):
... print 'Overloaded spam'
... def eggs(self):
... print 'Newly defined eggs'
>>> magicmethod(B.spam)
'overloaded'
>>> magicmethod(B.ham)
'inherited'
>>> magicmethod(B.eggs)
'newly defined'
>>> magicmethod(B.__init__)
'inherited'
"""}
For new-style classes, you have a method mro(), returning the method resulution order list. [0] is the class itself.
So you could do
>>> any(hasattr(i, 'ham') for i in B.mro()[1:])
True
>>> any(hasattr(i, 'spam') for i in B.mro()[1:])
True
>>> any(hasattr(i, 'eggs') for i in B.mro()[1:])
False
So eggs is newly defined.
>>> any(getattr(B, 'ham') == getattr(i, 'ham', None) for i in B.mro()[1:])
True
>>> any(getattr(B, 'spam') == getattr(i, 'spam', None) for i in B.mro()[1:])
False
So ham is inherited.
With these, you can craft your own heuristics.
Expanding on hamstergene's answer; a class stores its base classes in the class variable __bases__.
So:
>>> B.spam == B.__bases__[0].spam
False
>>> B.ham == B.__bases__[0].ham
True
>>> B.eggs == B.__bases__[0].eggs
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'A' has no attribute 'eggs'
>>> hasattr(B,"eggs")
True
>>> hasattr(B.__bases__[0],"eggs")
False

Python __str__: Magic Console

Suppose one decided (yes, this is horrible) to create handle input in the following manner: A user types in a command on the python console after importing your class, the command is actually a class name, the class name's __str__ function is actually a function with side effects (e.g. the command is "north" and the function changes some global variables and then returns text describing your current location). Obviously this is a stupid thing to do, but how would you do it (if possible)?
Note that the basic question is how to define the __str__ method for a class without creating an instance of the class, otherwise it would be simple (but still just as crazy:
class ff:
def __str__(self):
#do fun side effects
return "fun text string"
ginst = ff()
>>ginst
What you are looking for is the metaclass
class Magic(type):
def __str__(self):
return 'Something crazy'
def __repr__(self):
return 'Another craziness'
class Foo(object):
__metaclass__ = Magic
>>> print Foo
Something crazy
>>> Foo
Another craziness
in console you're getting representation of your object, which __repr__ is responsible for. __str__ used for printing:
>>> class A:
def __str__(self):
return 'spam'
>>> A()
<__main__.A object at 0x0107E3D0>
>>> print(A())
spam
>>> class B:
def __repr__(self):
return 'ham'
>>> B()
ham
>>> print(B())
ham
>>> class C:
def __str__(self):
return 'spam'
def __repr__(self):
return 'ham'
>>> C()
ham
>>> print(C())
spam
You could use instances of a class rather than classes themselves. Something like
class MagicConsole(object):
def __init__(self, f):
self.__f = f
def __repr__(self):
return self.__f()
north = MagicConsole(some_function_for_north)
south = MagicConsole(some_function_for_south)
# etc

Getting the class name of an instance

How do I find out the name of the class used to create an instance of an object in Python?
I'm not sure if I should use the inspect module or parse the __class__ attribute.
Have you tried the __name__ attribute of the class? ie type(x).__name__ will give you the name of the class, which I think is what you want.
>>> import itertools
>>> x = itertools.count(0)
>>> type(x).__name__
'count'
If you're still using Python 2, note that the above method works with new-style classes only (in Python 3+ all classes are "new-style" classes). Your code might use some old-style classes. The following works for both:
x.__class__.__name__
Do you want the name of the class as a string?
instance.__class__.__name__
type() ?
>>> class A:
... def whoami(self):
... print(type(self).__name__)
...
>>>
>>> class B(A):
... pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>
class A:
pass
a = A()
str(a.__class__)
The sample code above (when input in the interactive interpreter) will produce '__main__.A' as opposed to 'A' which is produced if the __name__ attribute is invoked. By simply passing the result of A.__class__ to the str constructor the parsing is handled for you. However, you could also use the following code if you want something more explicit.
"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)
This behavior can be preferable if you have classes with the same name defined in separate modules.
The sample code provided above was tested in Python 2.7.5.
In Python 2,
type(instance).__name__ != instance.__class__.__name__
# if class A is defined like
class A():
...
type(instance) == instance.__class__
# if class A is defined like
class A(object):
...
Example:
>>> class aclass(object):
... pass
...
>>> a = aclass()
>>> type(a)
<class '__main__.aclass'>
>>> a.__class__
<class '__main__.aclass'>
>>>
>>> type(a).__name__
'aclass'
>>>
>>> a.__class__.__name__
'aclass'
>>>
>>> class bclass():
... pass
...
>>> b = bclass()
>>>
>>> type(b)
<type 'instance'>
>>> b.__class__
<class __main__.bclass at 0xb765047c>
>>> type(b).__name__
'instance'
>>>
>>> b.__class__.__name__
'bclass'
>>>
Alternatively you can use the classmethod decorator:
class A:
#classmethod
def get_classname(cls):
return cls.__name__
def use_classname(self):
return self.get_classname()
Usage:
>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'
Good question.
Here's a simple example based on GHZ's which might help someone:
>>> class person(object):
def init(self,name):
self.name=name
def info(self)
print "My name is {0}, I am a {1}".format(self.name,self.__class__.__name__)
>>> bob = person(name='Robert')
>>> bob.info()
My name is Robert, I am a person
Apart from grabbing the special __name__ attribute, you might find yourself in need of the qualified name for a given class/function. This is done by grabbing the types __qualname__.
In most cases, these will be exactly the same, but, when dealing with nested classes/methods these differ in the output you get. For example:
class Spam:
def meth(self):
pass
class Bar:
pass
>>> s = Spam()
>>> type(s).__name__
'Spam'
>>> type(s).__qualname__
'Spam'
>>> type(s).Bar.__name__ # type not needed here
'Bar'
>>> type(s).Bar.__qualname__ # type not needed here
'Spam.Bar'
>>> type(s).meth.__name__
'meth'
>>> type(s).meth.__qualname__
'Spam.meth'
Since introspection is what you're after, this is always you might want to consider.
You can simply use __qualname__ which stands for qualified name of a function or class
Example:
>>> class C:
... class D:
... def meth(self):
... pass
...
>>> C.__qualname__
'C'
>>> C.D.__qualname__
'C.D'
>>> C.D.meth.__qualname__
'C.D.meth'
documentation link qualname
To get instance classname:
type(instance).__name__
or
instance.__class__.__name__
both are the same
You can first use type and then str to extract class name from it.
class foo:pass;
bar:foo=foo();
print(str(type(bar))[8:-2][len(str(type(bar).__module__))+1:]);
Result
foo
If you're looking to solve this for a list (or iterable collection) of objects, here's how I would solve:
from operator import attrgetter
# Will use a few data types to show a point
my_list = [1, "2", 3.0, [4], object(), type, None]
# I specifically want to create a generator
my_class_names = list(map(attrgetter("__name__"), map(type, my_list))))
# Result:
['int', 'str', 'float', 'list', 'object', 'type', 'NoneType']
# Alternatively, use a lambda
my_class_names = list(map(lambda x: type(x).__name__, my_list))

Categories