Why do base classes in Python need to extend object? - python

I'm looking for a clear explanation of why my base classes must extend object if I want to use super
# Without extending object, this code will fail with
# TypeError: must be type, not classobj
class A(object):
def __init__(self):
print "Called A.__init__"
class AChild(A):
def __init__(self):
super(AChild, self).__init__()
print "Called AChild.__init__"
AChild()
This works as expected, but if you remove object it throws the exception mentioned. I'm using Python 2.7.8. Feel free to link me to any related questions, but I didn't find a good answer with a quick search

It's because by extending object you are using new style classes which are required to support the use of super, which was added alongside the introduction of new style classes to Python.
According to the information in this answer, old style classes had a simple depth-first method resolution order so there was no need for this function, and thats probably why it wasn
t included then. However upon adding multiple inheritance, super is now the recommended way to call a superclass because of the more complicated MRO.

Related

Call the method of the super class in an other method of the subclass

I already asked about something related to the game I am developing. The Problem occured while the developement, but actually it has nothing to do with the game it self.
I have a method ('resize' in a subclass) in my Code which calls the equivalent method in it's super class ('resize' of the superclass).
Expected Behaviour: Super-resize calls Super-do_rotozoom
What happend: Super-resize called Sub-do_rotozoom
Here is a code Example:
Subclass:
def do_rotozoom(self):
# do rotozoom stuff of subclass
def resize(self,factor):
super().resize(factor)
self.do_rotozoom()
Superclass:
def do_rotozoom(self):
#do rotozoom stuff of superclass
def resize(self,factor):
self.factor = factor
self.do_rotozoom()
I found a workaround which involved calling super().do_rotozoom() in the Subclass method do_rotozoom() which then was called by the super().resize(). I also found out, that I could in this case remove the line self.do_rotozoom().
In this case it was a pretty easy fix, but what would I do in a more complex scenario, for example, if I need to call the method do_rotozoom() with other variables in the superclass than I do in the subclass/another specific implementation? In other words, how am I able to select which method I want to use in a specific context?
Normaly you are only able to reach the super-methods from the subclass, but no super-methods (not of it's superclass but it's own methods) from the superclass.
I have not found a better title... :D
Developers tend to prefer Composition over inheritance , it's much more manageable .
what i advise you to do is to include an instance of your superclass in you subclass and use it whenever you want to .
The very definition of a subclass is that it inherits everything from the superclass except the methods and attributes it overrides.
A subclass can refer to its superclass and its method implementations with super(), like you already do in your example.
Either don't override do_rotozoom, or refer to the superclass method with super().do_rotozoom() where that's the behavior you require.

How to tell if a class is abstract in Python 3?

I wrote a metaclass that automatically registers its classes in a dict at runtime. In order for it to work properly, it must be able to ignore abstract classes.
The code works really well in Python 2, but I've run into a wall trying to make it compatible with Python 3.
Here's what the code looks like currently:
def AutoRegister(registry, base_type=ABCMeta):
class _metaclass(base_type):
def __init__(self, what, bases=None, attrs=None):
super(_metaclass, self).__init__(what, bases, attrs)
# Do not register abstract classes.
# Note that we do not use `inspect.isabstract` here, as
# that only detects classes with unimplemented abstract
# methods - which is a valid approach, but not what we
# want here.
# :see: http://stackoverflow.com/a/14410942/
metaclass = attrs.get('__metaclass__')
if not (metaclass and issubclass(metaclass, ABCMeta)):
registry.register(self)
return _metaclass
Usage in Python 2 looks like this:
# Abstract classes; these are not registered.
class BaseWidget(object): __metaclass__ = AutoRegister(widget_registry)
class BaseGizmo(BaseWidget): __metaclass__ = ABCMeta
# Concrete classes; these get registered.
class AlphaWidget(BaseWidget): pass
class BravoGizmo(BaseGizmo): pass
What I can't figure out, though, is how to make this work in Python 3.
How can a metaclass determine if it is initializing an abstract class in Python 3?
PEP3119 describes how the ABCMeta metaclass "marks" abstract methods and creates an __abstractmethods__ frozenset that contains all methods of a class that are still abstract. So, to check if a class cls is abstract, check if cls.__abstractmethods__ is empty or not.
I also found this relevant post on abstract classes useful.
I couldn't shake the feeling as I was posting this question that I was dealing with an XY Problem. As it turns out, that's exactly what was going on.
The real issue here is that the AutoRegister metaclass, as implemented, relies on a flawed understanding of what an abstract class is. Python or not, one of the most important criteria of an abstract class is that it is not instanciable.
In the example posted in the question, BaseWidget and BaseGizmo are instanciable, so they are not abstract.
Aren't we just bifurcating rabbits here?
Well, why was I having so much trouble getting AutoRegister to work in Python 3? Because I was trying to build something whose behavior contradicts the way classes work in Python.
The fact that inspect.isabstract wasn't returning the result I wanted should have been a major red flag: AutoRegister is a warranty-voider.
So what's the real solution then?
First, we have to recognize that BaseWidget and BaseGizmo have no reason to exist. They do not provide enough functionality to be instantiable, nor do they declare abstract methods that describe the functionality that they are missing.
One could argue that they could be used to "categorize" their sub-classes, but a) that's clearly not what's going on in this case, and b) quack.
Instead, we could embrace Python's definition of "abstract":
Modify BaseWidget and BaseGizmo so that they define one or more abstract methods.
If we can't come up with any abstract methods, then can we remove them entirely?
If we can't remove them but also can't make them properly abstract, it might be worthwhile to take a step back and see if there are other ways we might solve this problem.
Modify the definition of AutoRegister so that it uses inspect.isabstract to decide if a class is abstract: see final implementation.
That's cool and all, but what if I can't change the base classes?
Or, if you have to maintain backwards compatibility with existing code (as was the case for me), a decorator is probably easier:
#widget_registry.register
class AlphaWidget(object):
pass
#widget_registry.register
class BravoGizmo(object):
pass

Learn Python the Hard Way: exercise 40 - what is "object" and "self" in class definition?

Below is some code from Learn Python The Hard Way
Exercise 40: Modules, Classes, And Objects
I can't seem to figure out why is there a parameter for class MyStuff(object).
What's the reason to put object in the parentheses?
class MyStuff(object):
def __init__(self):
self.tangerine = "And now a thousand years between"
def apple(self):
print "I AM CLASSY APPLES!"
I have looked through some of the articles here on StackOverflow but failed to understand what's new object and old class object.
Could someone please explain the meaning of object in the class definition?
What happens if I leave that the parentheses empty when I declare my class?
Also there is a (self) argument for the 2 functions in the code.
In the book it says "self" is an empty object python created while instantiating an object with class.
But why stating the argument before the actual use of it??
I have been learning programming for 2 weeks only so I apologize if the question is too superficial, thank you for your time~
As per your comment, I see you are using Python 2. In Python 2.2 they introduced "New-style" classes, but kept "Classic" classes for backwards-compatibility reasons. In Python 3.0 or newer, classic classes are gone - every class is a new-style class (regardless of syntax).
For python 2.2-2.7, syntactically a new-style class is declared by subclassing from object explicitly (unless it has a different parent class):
class MyStuffNew(object):
a=1
while omitting the object reference creates a classic class:
class MyStuffClassic():
a=1
Functionally, they work almost the same, but there are a few differences between them in the builtin language definitions. For example, New-style classes introduced a builtin class method __mro()__ (method resolution order) which is used by the interpreter to work out which method (in the class inheritance heirarchy) you meant to call. This inbuilt method is missing in old-style classes (and the method resolution order is different, which can lead to some unexpected behaviour). For more information about New-style vs Classic classes, please read this Python Wiki page.
As mentioned above, in Python3 or above, the syntax used doesn't matter; all classes are new-style. However, many coders will use the class MyClass(object): syntax to maintain code compatibility with Python2.7. - Please see this answer.
In any version of the Python language, class MyChildClass(ParentClass): defines an inheritance relationship - MyChildClass is a child of ParentClass and will inherit all of its methods and fields.
The self is the way Python knows this is a member method and not a static function of your class. You can only access member fields and methods from within your class by using self.field and self.myMethod(var1,var2), etc.
When you actually call these functions from other places in your code, you don't pass a value to self - it is the variable that you are using. For example:
stuff = MyStuff()
stuff.apple()
# outputs "I AM CLASSY APPLES!"
print stuff.tangerine
# outputs "And now a thousand years between"
stuff.tangerine = "Something else."
print stuff.tangerine
# outputs "Something else."
stuff2 = MyStuff()
print stuff2.tangerine
# outputs "And now a thousand years between"
If you don't include self in the method definition, calling mystuff.apple() will result in a runtime error because implicitly it's the same thing as calling MyStuff.apple(mystuff) - passing the instance of your MyStuff class into the apple function.

what does python class take in arguments

I am confused on what the folowing means:
class class_name(object):
What does the class takes in between the parenthesis? is it inheritance?
It's the superclass. There can be more than one, though getting that right and making it useful can be a bit tricky. There can also be none, but unless you're on Python 3, that's a bad idea.
Basically it is inheritance. You might find this thread and some of the related links useful: Python class inherits object.
Yes. It's inheritance. This is what it looks like:
class DerivedClass(BaseClass)
In your declaration, you're basically inheriting the object type. It's a built-in. However, in Python 3 you don't need to do this, as every class is implicitly a subclass of object.
By the way, more about this here.
class class_name(object):
This is called inheritance
Python also supports multiple inheritance , that means you can inherit from multiple classes
for example:
class class_name(BaseClassName1,BaseClassName2,BaseClassName3):

Python inheritance - referring to specific levels

I'm having trouble with Python (2.7) inheritance. I'm trying to refer from derived classes to parents and back, which is easy enough if you hard-code the classes, but that seems like an ugly approach to me. Is it? Anyway, here we go:
class Alpha(object):
def fie(self):
pass
class Beta(Alpha):
def fie(self):
super(self.__class__, self).fie()
class Gamma(Beta):
pass
Alpha().fie()
Beta().fie()
Gamma().fie()
The last one calls fie as defined on Beta, but since it's called from Gamma, the super will refer to Beta. As such it'll call itself again and starts an infinite recursion.
Is there a way to reference the class for which the function is initially defined? Or the class highest up the chain (besides object)? Or possibly an even better way to accomplish this without hard-coding class names?
Nope - you just have to write it as:
class Beta(Alpha):
def fie(self):
super(Beta, self).fie()
See: http://yergler.net/blog/2011/07/04/super-self/ - and quoted from there (as it explains it better than I could!):
According to the Python 2.7.2 standard library documentation, super “return[s] a proxy object that delegates method calls to a parent or sibling class of type.” So in the case of single inheritance, it delegates access to the super class, it does not return an instance of the super class. In the example above, this means that when you instantiate B, the follow happens:
enter B.__init__()
call super on B and call __init__ on the proxy object
enter A.__init__()
call super on self.__class__ and call __init__ on the proxy object
The problem is that when we get to step four, self still refers to our instance of B, so calling super points back to A again. In technical terms: Ka-bloom.
And within that article is a link to a blog by Raymond Hettinger (and they're always worth reading): http://rhettinger.wordpress.com/2011/05/26/super-considered-super/
NB: read the comment where a user suggests using type(self) (equiv to your self._class_) and why it doesn't work

Categories

Resources