1. Sending Mail
The smtplib
module provides a quick and easy way
to send e-mail messages.
This module contains a class called SMTP
that initiates a connection to a mail server.
In the CS labs, you can use mail.eecs.berkeley.edu
.
Elsewhere, you will have to choose a server that's willing
to deliver mail for you (such as the one provided by your ISP).
Instances of the SMTP
class provide a
sendmail()
method, which you can call with three arguments:
the sender's address, the receiver's address, and the message.
The message should be a multi-line string with the headers at the beginning
(such as Date:
or Subject:
),
followed by a blank line,
and then the body of the message.
When you're done with a connection, call its close()
method.
>>> message = '''Subject: test message ... Date: Tue, 4 Mar 2003 17:06:16 -0800 (PST) ... ... Hello!''' >>> >>> import smtplib >>> s = smtplib.SMTP('mail.eecs.berkeley.edu') >>> s.sendmail('gremlins@underthebed.net', 'me@mydomain.com', message) {} >>> s.close() >>>
Q1. Send a message to yourself – any message you like.
2. Fetching Pages
The urllib
module
lets you easily download Web pages (or anything else from the Web).
Calling urllib.urlopen()
on a URL
returns a file-like object (sometimes we call this a stream).
You can read all the data by calling read()
on this stream,
read the data one line at a time by calling readline()
,
or read a list of all the lines of the file with readlines()
.
>>> import urllib >>> stream = urllib.urlopen('http://example.com') >>> print stream.read() <HTML> <HEAD> <TITLE>Example Web Page </HEAD> <body> <p>You have reached this web page by typing "example.com", "example.net", or "example.org" into your web browser.</p> <p>These domain names are reserved for use in documentation and are not available for registration. See <a href="http://www.rfc-editor.org/rfc/rfc2606.txt">RFC 2606</a>, Section 3.</p> </BODY> </HTML> >>>
If you need to find out other information
about the downloaded file,
the received headers are stored in a dictionary
in stream.headers
.
>>> stream.headers.keys() ['last-modified', 'content-length', 'etag', 'date', 'accept-ranges', 'content-type', 'connection', 'server'] >>> stream.headers['content-type'] 'text/html' >>> stream.headers['last-modified'] 'Wed, 08 Jan 2003 23:11:55 GMT' >>>
Q2.
Get the top headline from Google News.
If you download http://news.google.com/
,
it turns out that each headline is on a line
that contains the string class=y
.
Just look for that and print the first such line.
The find()
method on strings will come in handy.
You can use the regular expression <[^>]*>
to match HTML tags and remove them.
Q3. Put these two pieces together to get a script that will e-mail you the top headline from Google News.
3. Operating System Functions
The os
module
provides all the system and file functions you might expect.
Commonly used functions from this module include:
listdir(path)
: return a list of the files in a directorychdir(path)
: change the current directorymkdir(path)
: create a new directoryrmdir(path)
: remove a directoryrename(old, new)
: rename (or move) a fileunlink(path)
: unlink (delete) a filesystem(command)
: run a system command
Unix-heads will also recognize functions such as
fork()
,
waitpid(pid, options)
,
link(source, dest)
,
symlink(source, dest)
,
readlink(path)
,
popen(command, mode)
,
and kill(pid)
.
Look at the list of functions in help(os)
for more.
If you don't know what all of these do, that's okay. I'm just mentioning them here so you know they're available, and you can find them if you need to use them.
The os
module also contains a submodule,
os.path
, specifically for manipulating paths.
Here are some useful functions in os.path
:
exists(path)
: test whether a path existsisdir(path)
: test whether a path is a directoryisfile(path)
: test whether a path is an ordinary filegetatime(path)
: get access time of a filegetmtime(path)
: get modification time of a filegetsize(path)
: get size of a file
There are more; again, look at help(os.path)
for anything having to do with file paths.
4. Class Objects
Everything in Python is an object. Certain other languages like to say this, but they don't really mean it. In Python, we really mean it. Numbers, strings, lists, dictionaries, and instances are objects; but functions, modules, classes, and methods are objects too.
Classes have their own namespaces,
just as modules and instances do.
Last time, we just talked about defining methods in classes.
But you can write any statements inside a class, if you want.
What really happens is that
the whole block inside the class
keyword
just gets executed inside the namespace of the class.
Any definitions or assignments are left in that namespace.
>>> class Foo: ... a = 3 ... def noogie(self): ... return self.a ... >>> Foo <class __main__.Foo at 0x81532b4> >>> Foo.a 3 >>> Foo.b = 4 >>> Foo.b 4 >>>
Try creating an instance of Foo
.
Call its noogie()
method.
What happens? Do you understand why?
Now try setting Foo.a
to some other number.
What happens when you call the noogie()
method
of the instance you just created?
Now create a second instance of Foo
.
Try setting the a
attribute directly on that instance.
Now what happens to the a
attribute of the first instance,
or of the class?
Explore the behaviour of the class and instances
by setting and checking their attributes
until you feel you understand how they work.
(Keep in mind that you can also remove assignments
using del
, as in del Foo.a
,
if that helps to clear things up as you experiment.)
Q4.
Draw a picture showing the relationships
between the Foo
class
and the two instances you just created,
showing how the value of the a
attribute is determined.
Call me over and show me your picture.
5. Functions and Methods
Define a function outside the class, such as this one:
>>> def ribbit(self, z): ... print self, z ... >>>
Try assigning this function to an attribute of a Foo
instance.
What happens when you try to call it on the instance?
What happens when you try to call it on the class?
Try assigning this function to an attribute of the Foo
class.
What happens when you try to call it on the class?
What happens when you try to call it on a previously-created instance?
What happens when you try to call it on a newly-created instance?
See if you can figure out what is happening. Ask me if you are confused.
Q5. Draw a picture showing how the class and instance behave when functions are assigned to their attributes, and showing what happens when you retrieve attributes that refer to functions. Call me over and show me your picture.
6. Inheritance
You can define a class that is derived from another class by giving the other class name in parentheses, like this:
>>> class Wong(Foo): ... def meow(self): ... return self.noogie() + 1 ... >>>
The result is a class with two callable methods:
noogie()
and meow()
.
Try creating an instance and calling its meow()
method.
You can test that this instance is an instance of the
Wong
class by asking isinstance(x, Wong)
(assuming your instance is called x
).
Notice that isinstance(x, Foo)
is also true,
because Wong
is a subclass of Foo
.
This is also the preferred way to check types;
for example, isinstance(3, int)
is true.
What happens if you set the a
attribute
on the Wong
class and call the
instance's meow()
method again?
How about if you set the a
attribute
on the Foo
class?
Q6.
Explain what happens when you call meow()
,
and explain which value of a
affects the result.
Now try this definition:
>>> class Wing(Wong): ... def noogie(self): ... return self.meow() + 1 ... >>>
What do you think will happen
when you call noogie()
on an instance of Wing
?
Try it.
If you want a method to call another method of a specific class, you call the method on the class, passing the instance as the first argument.
Q7.
What one change could you make, among the definitions of
Foo
, Wong
, and Wing
,
that would cause a call to noogie()
on an
instance of Wing
to add 1 to Foo.a
twice,
returning 5?
7. The Exception Hierarchy
The exceptions are actually classes, arranged in an inheritance hierarchy to represent how some exceptions are subcategories of others.
You can see this hierarchy by doing import exceptions
and then asking for help(exceptions)
. Try it.
Here are some of the most common exceptions used by Python programmers (as opposed to exceptions raised by Python itself):
TypeError
: an argument had the wrong type, or the wrong number of arguments was givenValueError
: an argument had a bad valueIOError
: something went wrong with reading or writing (e.g. a file is missing, corrupted, etc.)RuntimeError
: something went wrong inside the program (e.g. an internal variable somehow ended up with a bad value); this usually means there's a bug
When you catch exceptions using except
,
you catch not only exceptions that are exactly of the class you
specify, but also its subclasses.
8. Custom Exceptions
You can create your own classes of exceptions, to represent exceptional conditions more specifically than with the existing categories.
When you do this, you should define your exception
as a subclass of an appropriate existing exception.
If none of the specific errors is appropriate,
you can make your exception a subclass of
StandardError
, the superclass of all errors.
When you raise an exception,
you can create an instance of the exception and raise that.
You can define your exception to take whatever arguments it likes,
in order to record what caused the problem;
your exception class should then define a __str__
method
to produce the message that gets displayed.
Q8.
Define a custom exception that you might throw
to indicate that someone tried to create a Date
using a string in the wrong format.
Here's the seventh assignment.
If you have any questions about these exercises or the assignment, feel free to send me e-mail at bczestyca.