Classy Attributes (Classes Part 1)
September 26, 2011 2 Comments
Suitably classy music starts. Mix through to Wilde’s drawing room. A crowd of suitably dressed folk are engaged in typically brilliant conversation, laughing affectedly and drinking champagne.
Prince My congratulations, Wilde. Your latest play is a great success. The whole of London’s talking about you.
Oscar There is only one thing in the world worse than being talked about, and that is not being talked about.
There follows fifteen seconds of restrained and sycophantic laughter…
Ok, now it’s time to draw breath a little and talk about something I mentioned a couple of tutorials ago – classes. We’ve used heaps of classes so far without noticing them. Classes are all round useful things, and there’s absolutely no avoiding classes if you do any but the most trivial of programs in Python. But that’s no problem because classes are really really neat and using them (generally) will improve your programming and your programs. Once you start using them you’ll wonder how you ever did anything without them.
Let’s start by making a class:
>>> class allDads(object): ... pass ... >>> allDads <class '__main__.allDads'>
This defines a class called allDads (the pass statement is necessary, because Python expects a class to have statements setting out the innards of the class. We have used pass as a sort of do nothing innard. We will do a more interesting example in a later tute). The class allDads is said to “inherit from” object (ie the thing named in the brackets). Which is to say, all the functions and data that object has, allDads has as well. As everything in Python is an object, so too allDads is also an object. However, allDads is just a definition, it is not an instance. We can make an “instance” of allDads as follows:
>>> myDad = allDads() >>> myDad <__main__.allDads object at 0x7fa2c150f610>
Nota bene: until you’re more familiar with classes, you should always define your class as inheriting from object. That is always put “(object)” after the name of the class.
At the moment we’ve made a pretty boring class and a pretty boring instance. The difference between classes and instances is that a class is a general description, while an instance is a particular. Thus “all dads” is a class (that is, the class of men who are parents), but “my dad” is a particular instance of that class.
When classes store data it is called an attribute. Attributes are referenced by joining the class name with the attribute name by a dot. Here’s an example:
>>> allDads.appearance = "Hairy"
Here “appearance” is the name of the attribute, right before we first try to assign a value to it Python creates it. It has been assigned the value “Hairy”. Let’s retrieve the value we’ve stored there:
>>> allDads.appearance 'Hairy'
What’s more, since myDad is an instance of allDads, it has inherited the attribute from the assignment to the class:
>>> myDad.appearance 'Hairy'
However, the class doesn’t inherit from the instances (which makes sense – just because my dad has certain attributes doesn’t mean all dads do):
>>> myDad.description = "My dad is, like, so the best dad in the world. What's more, he's particularly self effacing." >>> myDad.description "My dad is, like, so the best dad in the world. What's more, he's particularly self effacing." >>> allDads.description Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'allDads' has no attribute 'description'
As far as Python is concerned the class allDads has no attribute called “description“, even though an instance of it (myDad) does. Let’s make another instance:
>>> thatSmellyKidsDad = allDads() >>> thatSmellyKidsDad.appearance 'Hairy' >>> thatSmellyKidsDad.description Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'allDads' object has no attribute 'description'
Here we’ve made a second instance of allDads called thatSmellyKidsDad. thatSmellyKidsDad inherits the attribute appearance that the class has, but it doesn’t have the attribute we gave to the specific instance myDad. The inheritance occurs at the time the instance is created. If you change the value of an instance later it doesn’t affect the attribute stored in any other instance, even if the attribute is inherited from the same class attribute.
Exercise 1: assign a different value to myDad.appearance and see if it changes thatSmellyKidsDad.appearance
Exercise 2: assign a different value to allDads.appearance and see if it changes myDad.appearance and thatSmellyKidsDad.appearance
Exercise 3: make some other attributes for myDad or thatSmellyKidsDad and assign values to them.
Use this function to show all the attributes you’ve been adding:
def showAttributesOfInstance(c): for i in dir(c): if i[:2] != "__": # not a reserved attribute or function if not callable(i): # not actually necessary as you can't define methods yet print "%s:\t%s"%(i,c.__getattribute__(i)) >>> myDad.age = "28 and some months" >>> showAttributesOfInstance(myDad) age: 28 and some months appearance: Hairy description: My dad is, like, so the best dad in the world. What's more, he's particularly self effacing.
Extra Extra Bonus Points: understand how showAttributesOfInstance() uses introspection to do what it does.
Just as you can store data in a class you can also store functions in a class. When data is stored in a class it’s called an attribute. When a function is stored in a class, it’s called a method. – But more on that later.