Point 1:
Some history required here... Originally Python had two distinct kind of types, those implemented in C (whether in the stdlib or C extensions) and those implemented in Python with the class
statement. Python 2.2 introduced a new object model (known as "new-style classes") to unify both, but kept the "classic" (aka "old-style") model for compatibility. This new model also introduced quite a lot of goodies like support for computed attributes, cooperative super calls via the super()
object, metaclasses etc, all of which coming from the builtin object
base class.
So in Python 2.2.x to 2.7.x, you can either create a new-style class by inheriting from object
(or any subclass of object
) or an old-style one by not inheriting from object
(nor - obviously - any subclass of object
).
In Python 2.7., since your example Stack
class does not use any feature of the new object model, it works as well as an 'old-style' or as a 'new-style' class, but try to add a custom metaclass or a computed attribute and it will break in one way or another.
Python 3 totally removed old-style classes support and object
is the defaut base class if you dont explicitely specify one, so whatever you do your class WILL inherit from object
and will work as well with or without explicit parent class.
You can read this for more details.
Point 2.1 - I'm not sure I understand the question actually, but anyway:
In Python, objects are not fixed C-struct-like structures with a fixed set of attributes, but dict-like mappings (well there are exceptions but let's ignore them for the moment). The set of attributes of an object is composed of the class attributes (methods mainly but really any name defined at the class level) that are shared between all instances of the class, and instance attributes (belonging to a single instance) which are stored in the instance's __dict__
. This imply that you dont define the instance attributes set at the class level (like in Java or C++ etc), but set them on the instance itself.
The __init__
method is there so you can make sure each instance is initialised with the desired set of attributes. It's kind of an equivalent of a Java constructor, but instead of being only used to pass arguments at instanciation, it's also responsible for defining the set of instance attributes for your class (which you would, in Java, define at the class level).
Point 2.2 : self
is the current instance of the class (the instance on which the method is called), so if s
is an instance of your Stack
class, s.push(42)
is equivalent to Stack.push(s, 42)
.
Note that the argument doesn't have to be called self
(which is only a convention, albeit a very strong one), the important part is that it's the first argument.
How s
get passed as self
when calling s.push(42)
is a bit intricate at first but an interesting example of how to use a small feature set to build a larger one. You can find a detailed explanation of the whole mechanism here, so I wont bother reposting it here.