Classes (introduction)

COMMENT: This is my attempt at rewriting the introduction to the Classes section, to make it… useful. This was orginally hosted at parlar.infogami.com

COMMENT: The target audience for this page is “people with some programming experience, but with little or no OO experience”. For discussion, see the comments section.

What’s a class? #

If you’re coming to Python from an object-oriented programming language (C#/Java/Smalltalk/Ruby, etc), then you can probably skip over this section (though you might want to skim over the parts where I discuss self)

If Python is your first programming language though, or your first encounter with object oriented programming, then you’re definitely going to want to read this.

Objects and Classes #

Without getting technical, an object is the basic Python building block, the ‘lego brick’ with which every program is built. All the elements that we’ve met up until now - integers, strings, lists, functions etc. - they’re all objects. And a class is simply a user-defined object that lets you keep a bunch of closely related things “together”. COMMENT:Not sure about this paragraph - Gerard

Let’s take a simple example to see why you would want classes. First we’ll write some code in a non-OO procedural fashion, and then we’ll see how the same code can be written with classes.

The Procedural Approach #

Imagine that you’re a teacher and, after going through the first few chapters of this tutorial, you’ve decided to build a little python program to keep track of some stats for your students.

So how do you start? Well, the first thing you want is a list of your students:

 
>>> student_list = ["Simon", "Mal", "River", "Zoe", "Jane", "Kaylee", "Hoban"]

(We’ll implement the program in the interactive interpreter, for the sake of the example, but in real life, you’d put this stuff into actual modules. I’ll interspere the interpreter code with comments, but keep in mind that all this code goes together.)

You know how fickle the administration is, and with the housing market the way it is, people are moving all the time. So you’re definitely going to need ways to add and remove kids from the list.:

>>> def add_student(student):
...     student_list.append(student)
...
>>> def remove_student(student):
...     student_list.remove(student)
...
>>> remove_student("Mal")
>>> add_student("Bill")
>>> print student_list
["Simon", "River", "Zoe", "Jane", "Kaylee", "Hoban", "Bill"]

Ok, so that works nicely. What now? Well, it’d be nice to track the grades of each student. Probably the easiest way to do that is to create a dictionary, where each key in the dict is a student name, and each value is a list of their marks.

>>> student_marks = {}
>>> for student in student_list:
...     student_marks[student] = []
...

So there we’ve initialized our student_marks, with no marks for any student yet. So now we should make a function to add marks.

>>> def add_mark(student, mark):
...     student_marks[student].append(mark)
...

What if we want a function to change the mark though? That’s a lot tricker. To change a mark, we need to know a few things. First, we need to know the student, that’s easy. Second, we need to know where in the value of student_marks[student] the old mark existed, or we need to know what the old mark is. Here is a possible way to do this:

>>> def change_mark(student, oldmark, newmark):
...     # If you know the old mark
...     temp_mark_list = student_marks[student]
...     position = temp_mark_list.index(oldmark)
...     temp_mark_list[position] = newmark

So we’ve given a simple way to change the marks, if you know the old mark and the new mark you want to use.

As a final function, let’s add a class attendance feature. We’ll assume that most days, the entire class will be there. So the function will, by default, say that everyone one was there on a certain day. We will though pass in an optional list of names of people who weren’t there.

First, we need another dictionary, to track attendance:

>>> student_attendance = {}
... for student in student_list:
...     student_attendance[student] = 0

This time, we’re initializing the list with zeros, ie. the number of days they’ve attended class. Every day, that number will increase by one for each student who is there.

 
>>> def another_day(absent = []):
...     for student in student_list:
...         if student not in absent:
...             old_attendance = student_attendance[student]
...             student_attendance[student] = old_attendance + 1

So now we can call another_day, and pass in an optional list of students who aren’t there. Everyone else will have their attendance increase by 1.

So this is great and all, and works fine right now. But what if want want to start adding a bunch of other teaching related functions, lists and dictionaries into this file? Suddenly, at the top level of the file, we’ll have a lot of different lists defined (like student_attendance, student_marks, etc.), a whole lot of functions (another_day, add_mark, etc.) and no way to tell what goes together with what. In other words, which functions need which variables, how is everything related?

And this is essentially what classes do. They provide “encapsulation”, a method of grouping together things that logically relate to each other.

The Object-Oriented Approach #

So how do we do this? The first thing we have to do is create a “class”. The class is the “thing” that will group together common elements.

The Student Class

So far, for each student in the class, we’ve been tracking a lot of different things, in different variables. We’re tracking the student’s name (in student_list), then we have a mapping between their name and their marks (student_marks), and a mapping between the name and their attendance (student_attendance). It’d be really nice to keep all the information for each student together, in one place. Hence, a Student class:

COMMENT: Original - So how do we do this? The first thing we have to do is create a “class”. The class is the “thing” that will group together common elements. Let’s call our first class Student. For each student in the class, so far, we’re tracking a lot of different things, in different variables. We’re tracking the student’s name (in student_list), then we have a mapping between their name and their marks (student_marks), and a mapping between the name and their attendance (student_attendance). It’d be really nice to keep all the information for each student together, in one place.

>>> class Student:
...     def __init__(self, name):
...         self.name = name
...         self.attendance = 0
...         self.marks = []

Ok, so some of that definitely looks kind of crazy at this point, but some probably makes some sense. For instance, self.attendance = 0 and self.marks = [] should look at least a bit familiar, and should make a little bit of sense.

But what exactly are we doing here? Well, first off, we’re declaring that we are creating a new class, with class Student(object). The name of this class is Student.

So, that’s fine, nothing too tough there. But what is that next silly looking thing, the __init__(self, name)? That’s called a “constructor”. It is a special function of the class that is called whenever we create a new instance of the class. Wow, lots of terminology there. Maybe a simple example will help.

 
>>> class ExampleClass:
...     def __init__(self, some_message):
...         self.message = some_message
...         print "New ExampleClass instance created, with message:"
...         print self.message
...
>>> first_instance = ExampleClass("message1")
New ExampleClass instance created, with message:
message1
>>> second_instance = ExampleClass("message2")
New ExampleClass instance created, with message:
message2

So what have we done there? Well, we created a new type of class, called ExampleClass. In the constructor (__init__), we print out a message when a new instance gets created. After defining the class, we created two new instances, first_instance and second_instance. When we created them, we can see that the print statements in the __init__ function got called, and more importantly, the variable we passed to the class (ie. “message1” in ExampleClass("message1"), gets passed to the __init__ function.

Ok, so that’s fine, but what’s up with the self as the first argument to the __init__ function? Every function in a class (functions in classes are actually called “methods”, I’ll call them that from now on) has to take self as the first argument. For anyone coming from another object oriented language, this will seem VERY strange. For new programmers, it will just seem annoying. For now though, have faith that it’s needed, and you’ll understand why later.

After the self, you can start putting the “real” arguments to the method, the ones you care about. So what arguments did we define? Just some_message. And what is this some_message used for? Well, in this example, we used it when we did print some_message, but more interestingly, we used it to do self.message = some_message.

So what’s that all about? By doing self.message =, we created something called an “attribute”. An attribute (as the name implies), is a piece of information for the class. Once we assign that attribute, we can access it from outside the class, like so:

>>> first_instance.message
'message1'
>>> second_instance.message
'message2'

See that? We assigned the attribute in the __init__ constructor, and now, we can access that attribute from outside the class! Is the Student class making more sense now? Let’s create an example instance of it, and see what happens:

>>> bobby = Student("Bobby")
>>> bobby.name
'Bobby'
>>> bobby.attendance
0
>>> bobby.marks
[]

Isn’t that MUCH nicer than having to keep three separate lists/dictionaries? All the information for the student “Bobby” is kept in one single place, an instance of the Student class.

And remember, it’s not just from outside the class that you can access these atributes. You can of course access them from within the class. Any attribute tied to self (like we did with self.name, self.attendance and self.marks) essentially becomes a global variable to that instance. So anytime you do anything with that instance, the value of the attribute is still around. Any variables you create inside a class, that aren’t prepended with self will be local variables, only around during a particular call to a function.

Let’s see an example of that. We’ll redefine our Student class as follows:

 
>>> class Student:
...     def __init__(self, name):
...         self.name = name
...         self.attendance = 0
...         self.marks = []
...         number_of_marks = len(self.marks)
...         print "%s marks so far!" % number_of_marks
... 
>>> b = Student("Bobby")
0 marks so far!
>>> b.marks
[]
>>> b.number_of_marks
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: Student instance has no attribute 'number_of_marks'
>>>

So what happened there? In the __init__ function, we created three attributes, name, attendance and marks. We know they are attributes because we put the self in front of them. We also created a local variable though, number_of_marks. As stated above, local variables only hang around for as long as the function is executing. Once the __init__ function is done, any local variable created in it will go away. That’s why when we tried to do b.number_of_marks, we got an AttributeError exception.

And remember that values of attribute variables are unique to each instance. So if we do:

>>> b = Student("Bobby")
>>> m = Student("Mary")
>>> b.name
'Bobby'
>>> m.name
'Mary'

We can see that the b instance has its own value for the attribute name, and the m instance has its own value for that attribute.

So let’s get a bit fancier, let’s create a StudentTracker. This tracker will receive a list of student names as an argument to its constructor, and then will create a Student instance for EACH of those names:

>>> class StudentTracker:
...     def __init__(self, initial_student_list):
...         self.student_names = initial_student_list
...         self.students = {}
...         for name in self.student_names:
...             self.students[name] = Student(name)
...

So, we created a nice attribute, self.students, which is a dictionary of Student instances (or objects, it is common to call an instance an “object”). We still need to be able to do stuff with those instances though. The way we’ll do that is by defining some methods in the class.

A method is a function that is specific just to the class it’s defined in. Here’s a simple example:

>>> class Multiplier:
...     def __init__(self, number):
...         self.number = number
...     def multiply_by(self, x):
...         return self.number * x

So this class will have one attribute, self.number. It also has one method, multiply_by, which takes another number, multiplies it by our original number, and returns the result. Let’s see it in action.

>>> f = Multiplier(10)
>>> f.number
10
>>> f.multiply_by(5)
50
>>> f.number
10

Does that make sense? We created an instance, and called it f. We then showed the attribute, f.number. We then called the method on the class, by doing f.multiply_by(5), which returned 5*10. Notice though that in our definition of multiply_by, we don’t change the value of self.number, which is why it remains 10.

It is important to note how we called the method. We can’t just do multiply_by(5), we have to say f.multiply_by(5). Why is that? Well, imagine what would happen if we had created two separate instances. How is Python supposed to know which one to call, unless you tell it?:

>>> f = Multiplier(10)
>>> g = Multipler(20)
>>> f.multiply_by(5)
50
>>> g.multiply_by(5)
100

So we told Python which instance to call multiply_by on, and it did it, and everything worked perfectly!

So let’s get back to our StudentTracker. We haven’t yet defined any regular methods for it (we defined __init__, but that’s a special method, you’re not supposed to call it yourself. Having __ on both sides of the method means you’re not suposed to call it, it’s a special method that Python will call by itself).

Let’s redefine our Student, and StudentTracker, but this time with useful methods:

 
>>> class Student:
...     def __init__(self, name):
...         self.name = name
...         self.attendance = 0
...         self.marks = []
...     def add_mark(self, mark):
...         self.marks.append(mark)
...     def present(self):
...         self.attendance = self.attendance + 1
...     def get_average(self):
...         return sum(self.marks) / len(self.marks)
...     def change_mark(self, oldmark, newmark):
...         position = self.marks.index(oldmark)
...         self.marks[position] = newmark
...     def __str__(self):
...         message = "Name: " + self.name + " "
...         message = message + "Attendance: " + str(self.attendance)
...         message = message + "Average: " + str(self.get_average())
...         return message
>>> class StudentTracker:
...     def __init__(self, initial_student_list):
...         self.student_names = initial_student_list
...         self.students = {}
...         for name in self.student_names:
...             self.students[name] = Student(name)
...     def another_day(self, absent = []):
...         for name in self.student_names:
...             if name not in absent:
...                 self.students[name].present()
...     def add_mark(self, name, mark):
...         self.students[name].add_mark(mark)
...     def change_mark(self, student, oldmark, newmark):
...         self.students[name].change_mark(oldmark, newmark)
...     def prettyprint_students(self):
...         for student in self.students.values():
...             print student

Almost everything there should be pretty self explanatory at this point (except the __str__), but I’ll point out a few key ideas.

The __str__ method is another special method. It gets called when Python is told to convert something to a string (using the str() function), or when Python is told to print an instance. A small example is as follows:

>>> class Foo:
...     def __str__(self):
...         return "I am an instance of Foo!!!"
>>> f = Foo()
>>> print f
I am an instance of Foo!!!
>>> str(f)
'I am an instance of Foo!!!'

In our __str__ method, we build up a nice long message, including the student’s name, attendance, and mark average, and return that.

Note that in our __str__ method, we do self.get_average(). Just like when a class instance wants to access one of its own attributes, we must prepend the self. to the method call.

Reminder about self: Note again that all the methods we defined had self as their first argument, but when we actually call the method, it essentially gets ignored. That is a little bit of magic Python is doing for you. It should make sense when you get deeper into Python programming. For now, just trust that when you define a method, you need self as the first argument, but when you call a method, you can ignore the self.

Notice the short-hand in another_day and the StudentTracker versions of add_mark and change_mark. In another_day, we have the following line:

self.students[name].present()

You’ve probably figured out what that does, but just in case, I’ll explain it. Remember what self.students is, right? It’s a dictionary, where the keys are the students’ names, and the values are instances of the Student class. So if we do self.students[name], that returns an instance, right? So, we would normally do:

student = self.students[name]
student.present()

But, if the only thing we need to do with the instance right now is called one method, why waste space? We can instead just do what we did above, namely:

self.students[name].present()

So, the self.students[name] part of that is executed first, and it returns the instance object. It then does the .present() on the instance object. This is an idiom you’ll see all the time in Python code (and in most object-oriented programming languages), so make sure you understand it. We did the exact same thing in the StudentTracker version of add_mark, namely:

self.students[name].add_mark(mark)

And that ends our mini introduction to what classes are. The further sections in this chapter will go into more detail. I leave it as an exercise to the reader to actually try these out. Create a StudentTracker instance with some names, play around a bit, try to break the code (there’s no error handling, so there should be a few ways to break it). Messing around and experimenting with it will be the best way to learn.

And to continue with Python, it is pretty important that you learn how classes work. Most Python code is written with classes, most of the standad library is written with classes, it’s just the way things are done. So even if you don’t want to ever write your own classes, you’ll have to understand how they work if you want to use other peoples’ code.


Old Intro #

What’s a class? #

If you’re coming to Python from an object-oriented programming language (C#/Java/Smalltalk/Ruby, etc), then you can probably skip over this section (though you might want to skim over the parts where I discuss self).

If Python is your first programming language though, or your first encounter with object oriented programming, then you’re definitely going to want to read this.

A class, in simple terms, is a feature that lets you keep a bunch of closely related things “together”. Let’s take a simple example to see why you would want classes.

3rd Grade Class #

Assume that you’re the teacher of a 3rd grade class (you know, the type of class with a bunch of little kids running around, has nothing to do with programming languages). As the teacher, you’ve decided it’s a good idea to stay current with the hip, new technologies (like Python!) to keep your students from getting ahead of you.

So, after going through the first few chapters of this tutorial, you decided to build a little Python program to track some stats for your class. We’ll implement the program below in the interactive interpreter, for the sake of the example, but in real life, you’d put this stuff into actual modules. I’ll intersperse the interpreter code with comments, but keep in mind that all this code goes together.

So the first thing you want, is a list of students in your class. We’ll use a list, and not a tuple, because you never know when the administration is going to give you more students!:

 
>>> student_list = ["Simon", "Mal", "River", "Zoe", "Jane", "Kaylee", "Hoban"]

You know how fickle the administration is, and with the housing market the way it is, people are moving all the time. So you’re definitely going to need ways to add and remove kids from your class list.:

>>> def add_student(student):
...     student_list.append(student)
...
>>> def remove_student(student):
...     student_list.remove(student)
...

Ok, so that works nicely. What now? Well…

The Object-Oriented Approach #

So how do we do this? The first thing we have to do is create a “class”. The class is the “thing” that will group together common elements.

The Student Class

So far, for each student in the class, we’ve been tracking a lot of different things, in different variables. We’re tracking the student’s name (in student_list), then we have a mapping between their name and their marks (student_marks), and a mapping between the name and their attendance (student_attendance). It’d be really nice to keep all the information for each student together, in one place. Hence, a Student class:

>>> class Student(object):
...     def __init__(self, name):
...         self.name = name
...         self.attendance = 0

...         self.marks = []

Ok…

 

Comment:

That's kind of what I was thinking. Before we do that, I think I'd want to add some headers to break this up a bit better. Headers will also let us say "If you already understand the concept of classes, then skip ahead to X". I won't have time till next week though, all my school projects and exams will be done by Tuesday.

Posted by infogami

Comment:

If the goal was to create a nice hypertext version only, providing different paths through the tutorial would of course be easy. But I'm pretty sure the powers-that-be won't accept a hypertext-only version as a replacement for the current tutorial. Hmm. Maybe it would work if we just inserted this one before the current one?

Posted by infogami

Comment:

Yeah, I like yours better. Feel free to put it in, I've got to go study!

Posted by infogami

Comment:

Well, it's just IMHO and all - maybe others would disagree. I suppose this is the difficulty of writing or evaluating a tutorial, you're always trying to put yourself in someone else's shoes. I've added an alternative intro anyway, if you'd like to consider it. (it's at the end)

Posted by infogami

Comment:

Yeah... I was trying to be funny by calling it "A 3rd Grade CLASS"... Mission failed, I suppose. I have no strong emotional attachment to it, or any other use of the word "class" in that context. I'll change that sometime next week (or of course anyone else is invited to do it for me). And I'm definitely not advocating that this become the new Classes document, I wrote it to be the new introduction. As Fredrik suggested, it might work if my new stuff was just inserted in front of the current intro. The stuff in the current intro _is_ useful, and should be around somewhere, but a new reader probably shouldn't be assaulted with scopes and namespaces before seeing a single example of a simple class.

Posted by infogami

Comment:

Don't know if it works or not, but I've altered my alternative intro to mention objects, which would make it easier to write 'class Student(object)' but without having to talk about new-style/old-style.

Posted by infogami

Comment:

"core of all objects" seems like it'd be an incredibly confusing statement or idea for a beginner. By using a new-style class right at the beginning, you suddenly have the user faced with the idea of inheritance, and of the base `object` type. And I don't think we're putting a decision into the hands of the user in terms of whether they should use new or old style. I explcitly say in 9.2 that they should use new-style. It's only a problem to a user that decides to stop reading the tutorial right here. All I wanted to do with this section was introduce the concept and basic use of classes, which is easier when you're not adding new-style into the mix. Note again that in section 9.2, all the classes use new-style, because at that point, the user understands what a class is, and we can begin adding to that.

Posted by infogami

Comment:

+1 for using new-style classes from the beginning. Starting with tutorial, one presumably do not want to learn old features that are going to be deprecated later. And it is easy to understand that "object" means "the core of all objects". A small notice about old style classes somewhere would be fine. It is important (in a tutorial) to say "prefer this", "do not do this". Beginners (does not matter how experienced in other languages) need to be lead in the best direction. If they have to decide what is better to use on their own, they could be disappointed, misleaded, or simply delayed in the learning. Being a teacher, one have to show the authority to say "this is the best way for you, but not the only one".

Posted by infogami

Comment:

Wouldn't it be better to just use new-style classes from the start. You tell here that syntax is class Student: you might as well tell that it's: class Student(object): When people come back to the tutorial if they've forgotten how to create a class, and google sends them to this page, I think it would be better if it's written new-style here.

Posted by infogami

Comment:

Oh, and I forgot to mention, I purposely didn't use new-style classes for this introduction, because it means one less thing where we have to say "Trust us, we'll explain it later". Also note that I was the one that changed the current Classes documentation to use all new-style classes, so there is documentation describing one vs. the other.

Posted by infogami

Comment:

I think this is a good, well-written tutorial, but (IMO) it's let down by your use of 'A 3rd Grade CLASS' as an example - the two uses of the word 'Class' are confusing I think, and i can only imagine that this will be the same for the target audience, some of whom may not have English as a first language. Maybe it's possible to cut out some of the 'academic class of students' classes, eg. '... a teacher of the third-grade...' not '...a teacher of a third-grade class'? I think this is a better *introduction* to classes than the existing one, but the existing one contains a lot of essential stuff too. Perhaps Classes I, Classes II, with your version (Classes I) after Node5-data structures? (Also, I think you should use new-style classes).

Posted by infogami

Comment:

_(update: fixed markup)_ Just some more thoughts. Although I really like the style of this new section - informal, chatty, hands-on - it's slightly at odds with the plainer, dryer style of the rest of the tutorial. It feels like it's for a different, less-experienced audience. This fits in with an idea I keep having when reading the wiki - what about two tutorials, a beginners' and an intermediate? I imagine the Beginners tutorial as a kind of 'Python in 24 Hours' - something that someone serious could complete over a weekend, and that would give a good grounding in the basics. Then the Intermediate tutorial would be more in-depth, more real-world - basically the existing tutorial, but without whatever is covered in the Beginners. Suggested Beginners' Tutorial: * Audience1 - someone with experience of another language(s) who wants to learn Python from the ground up, possibly no OOP experience * Audience2 - someone with no programming experience but who doesn't want their hand held and is prepared to roll their sleeves up, maybe a technical/scientific background. * Using Python as a calculator - basic numeric types and operations, logical operators, precedence * Strings, lists, dictionaries * Control flow: if, for, while, range() * Functions, *args/**kwargs * Introduction to classes/OOP I understand that there are existing Beginners tutorials but I'm also thinking of this as a 'pruning' operation for this wiki. Obviously it's a big departure from the existing situation, but food for thought at least.

Posted by infogami

Comment:

So the only comment I ever got on this, when it lived at its old location, was that it missed the intended audience and should be in an appendix instead of as an intro to Classes. Thoughts on this? I do agree that I spend too much time describing what a class is (too much time for non-newbies), but I also believe that documentation filled with examples will teach a concept better than anything else.

Posted by infogami

Comment:

I've put together a suggested reorganisation [here](http://pytut.infogami.com/beginners) which includes this section. ( Don't worry about commenting on all this if you have exams - hope they're going well!)

Posted by infogami

Comment:

It is for a different audience, which is why I made the suggestion that a more advanced audience just skip over it. Something to think about though. And could you edit your list in the comment above? It's not wrapping around (Safari or Firefox), and now the screen scrolls pretty far to the right. (I'd do it, but it somehow feels wrong to edit someone else's comment)

Posted by infogami

Comment:

I quite like this, *except* for the way discussion of the self parameter is handled (Don't Worry It's Magic). Instead, I suggest introducing methods by pointing out that a method can be retrieved just like any other attribute by doing Student.a_method, and then invoked like any other function Student.a_method(instance, arg). And only *then* introduce instance.a_method(arg) as a shorthand for the above. I believe this tendency of tutorials to treat method invocations as if they're deep dark magic is at the heart of the resentment of the 'self' parameter. The reason that parameter is there is precisely because methods really *aren't* magic. They're just normal class attributes that happen to be functions.

Posted by infogami

Comment:

Fixed. Feel free to change little ones like that yourself though.

Posted by infogami

Comment:

Typo: >>> second_instance = ExampleClass(message2") needs another double quote within the parentheses.

Posted by infogami

Comment:

That's a good point. The analogy I'm thinking about is automobiles. The people at the factory have all the designs/blueprints for the car, but you can't drive a blueprint. You need to build actual instances of the plans to be able to do anything. And you can build multiple instances of a car from the same plans, all initially identical. Or something like that...

Posted by infogami

Comment:

I think you should be a little clearer about the making of instances. Making a class then making an instance from it is a jump for a beginner. Make some comment about a class being both a "container" that contains related stuff (as you did quite well) and also the class can be used as a template (cookie cutter) that can make a bunch of identical objects.

Posted by infogami

Comment:

I don't think that's implied. However, I prefer the version in the "Suggested Alternative Intro" anyway, so I'll probably change it to that sometime tomorrow.

Posted by infogami

Comment:

It's probably a bad idea to imply that the only reason for choosing a list over a tuple is the tuple's fixed length/contents. Tuples are most useful as weak structures for differenct kinds of objects. That is, they're conceivably an alternative to classes, in some situations.

Posted by infogami

Comment:

That sounds like a neat feature to try plugging into IPython. `doctest.DocTestParser` could be used at some level to parse out the interpreter characters and leave just the required code. Interesting...

Posted by infogami

Comment:

It'd be pretty cool if the Python interpreter ignored those marks. Considering they're being used in stuff like `doctest` as well, this makes a lot of sense.

Posted by infogami

Comment:

The reason I personally like showing the interpreter output is because it's much easier to show... the interpreter output. Like where I wrote `bobby.marks` and the output (empty list) was shown on the next line. That's never as clear when you do it without the >>> (and you can't copy and paste anyway, because if you start pasting in copied output, you'll get errors)

Posted by infogami

Comment:

Having >>> or ... before every line of code makes it really hard to copy paste the stuff into the interpreter. It seems like someone learning python might want to do that, instead of copying the code by hand to test things out.

Posted by infogami

A Django site. this page was rendered by a django application in 0.07s 2010-09-02 15:38:12.766779. hosted by webfaction.