Python Classes
Everything is an object
Thus far in Python we've been working with strings, numbers, lists, dictionaries, tuples... These are all types of objects in Python. Everything is an object, and every object has a type. Let's verify this:
>>> s = 'some string' >>> type(s) <type 'str'> >>> str <type 'str'> >>> type(s) is str True
Types and instances
So s we call an instance of the
str type. Let's look at an instance of
the list and bool types:
>>> mylist = [1,2,3] >>> type(mylist) <type 'list'> >>> myboolean = False >>> type(myboolean) <type 'bool'>
We must all learn to think as individuals
Why does it matter what type an object (or instance) is? For one
thing, it determines what methods you can call on it. Last week we saw
that if you have a string instance s, you can call
s.replace('a', 'b') to replace all 'a's in the string
with 'b's. But if you have a list mylist and you try to
call mylist.replace(...), you'll get an error. The
list type has no replace method, so list
instances don't either.
>>> mylist.replace('a', 'b')
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'list' object has no attribute 'replace'
User-defined types
str, list, dict,
bool, and tuple are all built-in
types. But we can also define our own user-defined types,
which are called classes. Most of you have probably
seen classes before, in Java or PHP or Perl (sort of).
A sample class
Let's say we're writing a blog engine. Clearly we'll need to work with blog posts. So we'll want a class to represent a blog post:
class BlogPost(object):
"""
A blog post with a title and content.
"""
def __init__(self, title, content=''):
self.title = title
self.content = content
The __init__ method is "magic": it's called whenever a new instance of your class is created. It's usually used for initialization, as we do here. (A "method" is just what we call a function when it belongs to a class).
Bring out your posts
>>> my_post = BlogPost('The Title')
>>> my_post.title
'The Title'
>>> my_post.content
''
>>> my_post.content = "Some really long content.\n\nAnother paragraph."
>>> print my_post.content
Some really long content.
Another paragraph.
That bird wouldn't FOOM if you put a million volts through it
So far our BlogPost objects are kind of... dead. They don't do anything. They can hold data (a title and some content), but they have no methods (besides __init__). Let's add one:
class BlogPost(object):
def __init__(self, title, content=''):
self.title = title
self.content = content
def get_first_paragraph(self):
"""
Return the first paragraph of this blog post's content.
"""
return self.content.split('\n\n')[0]
Trying out get_first_paragraph()
>>> my_post = BlogPost('The Title', "Some content.\n\n"
... "Another paragraph\n\n"
... "A third paragraph.")
>>> print my_post.content
Some content.
Another paragraph.
A third paragraph.
>>> print my_post.get_first_paragraph()
Some content.
Class inheritance
Our BlogPost class definition begins with the
line:
class BlogPost(object):
Our class inherits from the object
class. This means that, before we've written any further code, it
already has any methods defined on that class. In this
case, object is a generic base class, a blank slate. Any
class you write which doesn't inherit from some other class should
inherit from object. (You may see this referred to as a
"new-style" class; "old-style classes" inherit from nothing at all,
and are only for backwards-compatibility, they shouldn't be used in
new code).
Why use inheritance?
Use inheritance to create more specialized types
of general classes. For instance, some blog posts are really nothing
but a link to some external URL with a bit of commentary. It may be
useful to have a specialized LinkPost class for those
posts. LinkPosts are still BlogPosts too; if
we define new methods (or change existing methods)
on BlogPost, we want LinkPost to get those
changes automatically (we don't want to duplicate code and have to
change the same code two different places).
LinkPost
class LinkPost(BlogPost):
" A subclass of BlogPost for external links. "
def __init__(self, title, link, content=''):
super(LinkPost, self).__init__(title, content)
self.link = link
def get_first_paragraph(self):
first_para = super(LinkPost, self).get_first_paragraph()
return "\n".join([first_para, self.link])
Using LinkPost
>>> my_link = LinkPost('Check this out',
... 'http://www.example.com',
... 'What a beautiful example URL.')
>>> print my_link.get_first_paragraph()
What a beautiful example URL.
http://www.example.com
Homework
- Modify the
BlogPostclass so that it also has author and date attributes. - Add an
as_htmlmethod toBlogPostwhich returns (as a string) a simple HTML representation of the blog post, including all of its data attributes (title, author, date, content).