Classes¶
Python is like many other object-oriented languages: you can create classes to define new kinds of objects. A class defines the things that are common to a set of objects. Usually, these are methods, the functions callable on objects.
Basics¶
Here’s an example of a class:
class Greeter(object):
"""Object-oriented greetings"""
def __init__(self, name):
self.name = name
def greet(self, salutation="Hello"):
print("{}, {}".format(salutation, self.name))
As with functions, classes can begin with a string literal. This is the docstring that documents what the class does.
Methods (functions callable on objects) are defined just like regular functions, but indented in the body of the class. Methods always take “self” as a first parameter. This will be the object the method is being called on. Any time you want to access or update the attributes of the object, you use “self.attr_name”. There is no “object scope” in Python: methods need to explicitly use the self object passed to them.
Note
The explicit “self” parameter on every method might seem repetitive or wasteful. Other languages use an implicit reference to the object at hand. Python’s design is simplified by using an explicit self object like this, though it is a little hard to quickly explain how...
You make new objects from classes by calling the class, almost as if it were a function:
>>> greeter = Greeter("Ned")
When a new object is made, it is initialized by calling the __init__
method
on the object. __init__
is pronounced “dunder init”: dunder is short for
“double-underscore”. The new object is passed as self, and the arguments to
the class are passed as arguments after self. In this case, name
is equal
to “Ned”.
Then you can invoke methods on the object:
>>> greeter.greet()
Hello, Ned
When a method is invoked, the object (in this case, greeter) is passed as “self”. Other arguments used in the method call are passed as the rest of the arguments to the function. You can use defaulted and keyword arguments just as with regular functions:
>>> greeter.greet("Hola")
Hola, Ned
Access control¶
Python provides no facility for controlling access to an object’s attributes. There is no “private” or “protected”, everything is public. You may see people talking about “__private” names, which start with two underscores. They make it more difficult to get at attributes, but they are not meant for this purpose, and they don’t actually prevent code from looking at your attributes.
There is a convention in Python that names starting with an underscore (like
_name
) are not part of the public interface of a class (or module). The
underscore doesn’t stop someone from using the attribute if they are determined
to, but it provides a clear signal that they weren’t meant to use it.
Java and C++ place great importance on declaring access levels for object attributes. Python doesn’t have that ability. It relies much more on documentation to help programmers do the right thing.
Inheritance¶
Python classes can be created by inheriting from a base class:
class MyClass(MyBaseClass):
...
Objects made from MyClass will have all of the attributes and methods defined in MyClass, as well as all of the ones defined in MyBaseClass. MyClass can override methods defined in MyBaseClass simply by defining its own method with the same name.
Python also supports multiple inheritance, where a class can have two (or more!) base classes. This quickly gets complicated, so use it with caution.
Python has no formal notion of interfaces as Java does, though there are third-party packages that provide similar features.
Todo
Explain duck-typing?
Invoking overridden methods¶
If your class defines a method of the same name as a base class, you might want
to invoke the base class’ definition as part of your implementation. This is
very common in __init__
methods, where you want to make sure that every
class in the inheritance chain has a chance to do its initialization.
You can’t call the method directly, because self.__init__
will simply call
your own method again, causing an infinite loop. Python provides the
super()
function to walk up the inheritance chain to find the parent method
to call:
class MyClass(MyBaseClass):
def __init__(self):
super().__init__()
# .. do my initialization ..
or, in Python 2:
class MyClass(MyBaseClass):
def __init__(self):
super(MyClass, self).__init__()
# .. do my initialization ..
In Python 3, super()
is very clever and knows what to do automatically.
In Python 2, you need to tell it explicitly what class you are calling it from,
and also what object you are working with.
Special methods¶
Python classes can define how they interact with much of Python’s built-in syntax and machinery, by defining special methods, sometimes called magic methods. These are methods with dunder names: two leading underscores, and two trailing underscores.
We’ve already seen __init__
, which is automatically invoked to initialize
new objects. Generally, special methods are invoked by Python as it interacts
with your objects. Don’t call special methods directly, except to invoke an
overridden method in your base class.
There are dozens and dozens of special methods. If you want your object to behave like some built-in Python object, there is probably a special method you can define to do it.
As an example, __getitem__
is the method Python invokes when you use square
brackets with your object:
class DictPlusOne(object):
def __getitem__(self, key):
return key+1
>>> d1 = DictPlusOne()
>>> d1[10]
11
>>> d1[999]
1000