[Tutor] Help with understanding classes

RL Berman bermanrl at cfl.rr.com
Sat May 21 22:22:05 CEST 2011


What a phenomenally clear explanation.

Thank you very much, Steven.

Robert Berman

On 05/21/2011 07:49 AM, Steven D'Aprano wrote:
> On Sat, 21 May 2011 08:24:34 pm Robert Sjöblom wrote:
>> I'm trying to wrap my head around classes and their attributes, but
>> am having a hard time doing so. The websites and books that I have
>> consulted haven't been much help; most of them assume prior
>> programming/oop experience, something I lack.
> Let's start with a simple question -- what is an object? In programming,
> an object is a thing that combines data and behaviour together in one
> handy package. Back in the Dark Ages *wink*, code and behaviour were
> always separate, so you would have to design a data structure in one
> place of your program, then write functions to manipulate it somewhere
> else. If you had two different data structures which needed similar
> actions, you had to jump through hoops to keep the functions for one
> separate from the functions of the other.
>
> But objects let you keep related pieces of code together, so they don't
> get in the way of unrelated code with the same name:
>
> class Artist:
>      def draw(self):
>          print("I splashed paint on the canvas until it looked like"
>                " my mother on a rocking horse.")
>
> class GunSlinger:
>      def draw(self):
>          print("The stranger reached for his gun, but I was too"
>                " quick for him and plugged him full of lead.")
>
>
> The function (actually "method") called draw for Artists doesn't get
> over-ridden by the method with the same name for GunSlingers:
>
>
>>>> whistler = Artist()
>>>> wyatt_earp = GunSlinger()
>>>> whistler.draw()
> I splashed paint on the canvas until it looked like my mother on a
> rocking horse.
>>>> wyatt_earp.draw()
> The stranger reached for his gun, but I was too quick for him and
> plugged him full of lead.
>
>
> Here you see object code in action. You start with a class, which is
> something vaguely like a template. (It's actually nothing like a
> template, but that will do for now.) Before you can use the class, you
> normally have to instantiate it.
>
> Think of it like this: in the real world, "car" is a kind of machine, or
> if you prefer, a *class* of machine. But you can't just get into the
> abstract class of "car" and drive to the shops, you need an actual,
> concrete, physical car: an *instance* of the class. In object oriented
> programming ("OOP"), this is normally the same: you create an instance
> of the class, and then work with that. The instance gets its behaviour
> (and sometimes its data) from the class.
>
> The examples above are classes with behaviour only, no data or state.
> They never change. That's not very useful. Normally you want to store
> data in the class instance, sometimes in the class itself. Here's an
> example:
>
> class Paper:
>      colour = "white"
>      size = "A4"
>
> This defines a class with no behaviour, only state. In this case, it has
> two attributes, colour and size. The values stored in the class are
> global defaults: all Paper instances share the same value. But you can
> give individual instances their own independent value by assignment:
>
>>>> sheet = Paper()
>>>> sheet.colour
> 'white'
>>>> another_sheet = Paper()
>>>> another_sheet.size = "A5"  # cut the paper in half
>>>> another_sheet.colour = "green"  # and paint it
>>>> another_sheet.colour  # check that the change is stored
> 'green'
>>>> sheet.colour  # and check that the other sheet is unchanged
> 'white'
>
>
> Normally though, you don't need or want to set default state that
> applies to all instances. In the above Paper example, it is harmless,
> but sometimes it can lead to bugs, so be careful with class attributes.
>
> So although attributes common to all instances of a class can sometimes
> be useful, generally people try to avoid them, and it is more common to
> put off defining the instance's attributes until the instance is
> created. For that, Python has a special method called "__init__"
> (that's two underscores at the front and back). When you create an
> instance by calling Paper(), the __init__ method (if any) is
> automatically called by Python.
>
> class Paper:
>      def __init__(self, colour="white", size="A4"):
>          self.colour = colour
>          self.size = size
>
> Now the attributes no longer live inside the class, but inside the
> instance. Paper instances no longer share global state. Each instance
> gets its own independent attribute for colour and size, which you can
> specify when you create it:
>
>>>> sheet = Paper("blue", "Foolscap")
>>>> sheet.colour
> 'blue'
>
>
> Now, I've skimmed over a couple of important things here. Firstly,
> syntax: in Python, the syntax for attribute access is with a dot:
>
> paper.size
>
> lets you retrieve the attribute. To set the attribute, you simply assign
> to it:
>
> paper.size = "A3"
>
> Notice that dot is the same syntax used for accessing methods:
>
> whistler.draw()
>
> That's because in Python, methods are just another attribute, only you
> can call them with () syntax. This lets you do all sorts of cool and
> advanced things, like store a method somewhere to use it later:
>
> import random
> if random.random()<  0.5:
>      method = wyatt_earp.draw  # no parentheses!
> else:
>      method = whistler.draw
>
> # later...
> method()  # call the method
>
> but I digress.
>
> The other thing I glossed over was the mysterious "self" parameter in
> the method definitions. Remember, methods are defined inside the class,
> not inside the instance. When you call a method, how does the class
> know which instance it should look at? The answer is, Python does some
> sleight of hand in the background, changing what you write:
>
> whistler.draw()
>
> into what actually gets executed:
>
> Artist.draw(whistler)
>
> That's moderately advanced though, you don't need to care about it,
> *except* that you have to remember to declare a parameter in all your
> methods to hold that auto-magic instance argument. Conventionally, we
> call it "self", but you can call it anything you like. (You can, but
> you shouldn't.) Forgetting to declare "self" in your methods is one of
> the more common source of bugs.
>
>
> That's pretty much all you need to know to start using objects. There's
> a lot more though: inheritance, class methods and static methods (as
> opposed to ordinary methods), properties, descriptors (advanced!),
> slots, and more. But one step at a time.
>
> Any questions, don't hesitate to ask!
>
>
>


More information about the Tutor mailing list