Review
An object is an instance of a class
Class defines possible operations and states
Each instance is independent of all others
Object-oriented language supports:
Encapsulation: each instance manages all of its own state
Polymorphism: objects with the same operations are interchangeable
Inheritance: define new classes by extending existing ones
Reflection: programs can inspect themselves at run-time
Not part of the official definition
But very important in practice
Creating a Class in Python
A source file may define any number of classes
Start definition using class keyword
Followed by name of class
Starts an indentation block
Functions defined in class block are methods
Must have at least one argument
Represents the particular instance
Usually called self
Methods can be called anything
But method names beginning and ending with double underscore mean special things
E.g. __init__ is the class's constructor
Members created by assignment to self.whatever
A Simple Counter Class
class Counter:
# Constructor: 'self' is the object being constructed
def __init__(self):
self.value = 0 # Create a member variable 'value'
# Normal method: 'self' is the method's object
def step(self):
self.value += 1
def current(self):
return self.value
if __name__ == "__main__":
c = Counter()
print "initial value", c.current()
c.step()
print "after one step", c.current()
c.nonExistentMethod()
initial value 0
after one step 1
AttributeError: Counter instance has no attribute 'nonExistentMethod'
Encapsulation Revisited
Python doesn't enforce encapsulation
No equivalent of protected or private
Anyone can happily execute obj.value = "abc"
Generally a bad idea
New Classes From Old
Extend a parent class to create a child class
Put parent's name in parentheses after child's
Must invoke parent's constructor explicitly
Unlike Java, it can be called like any other method
from counter import Counter
class Stepper(Counter):
def __init__(self):
Counter.__init__(self)
def reset(self):
self.value = 0
Overriding Methods
Methods defined in child take precedence over those defined in parent
from counter import Counter
class Incrementer(Counter):
def __init__(self, increment=1):
Counter.__init__(self)
self.increment = increment
def step(self):
self.value += self.increment
if __name__ == "__main__":
objects = [["parent", Counter()],
["child", Incrementer(3)]]
for i in range(2):
for [name, obj] in objects:
obj.step()
print name, i, ":", obj.current()
parent 0 : 1
child 0 : 3
parent 1 : 2
child 1 : 6
Class Members
Variables defined directly in class belong to the class, not to instances
Like static in Java
Nothing equivalent (yet) for methods
Concept is easy
Coming up with a simple syntax has proved difficult
class Tracker:
numCreated = 0
def __init__(self):
Tracker.numCreated += 1
t1 = Tracker()
t2 = Tracker()
print Tracker.numCreated
2
Overloading Operators
Specially-named method associated with every arithmetic operator
__add__ for +, __mul__ for *, and so on
If x is an object, x+2 is really x.__add__(2)
Operators also have right-hand methods
E.g. __radd__, __rmul__
So 2+x is x.__radd__(2)
Execution order for a+b is:
If a has a method __add__, call a.__add__(b)
Else if b has a method __radd__, call b.__radd__(a)
Else use Python's built-in default
Modular Integer Class
Only takes on values 0..N-1
Automatically wraps around at N
class modInt:
def __init__(self, base):
self.base = base
self.value = 0
def __add__(self, other):
self.value += other
self.value %= self.base
return self
def val(self):
return self.value
if __name__ == "__main__":
a = modInt(3)
for i in range(5):
a = a + 1
print a.val()
1
2
0
1
2
Some Other Special Methods
__str__(self) |
Convert to string (e.g. for printing) |
__call__(self, args) |
Function call |
__getitem__(self, index) |
Indexing |
__contains__(self, item) |
Membership test |
__len__(self) |
Length |
__int__(self) |
Convert to integer |
Sparse Vector Class
Problem: want efficient storage when almost all elements are zero
Solution: store index/value pairs of non-zero elements in a dictionary
What is the length of a sparse vector?
Some maximum value specified by the user?
Largest current index?
Largest index seen so far?
We'll use largest index seen so far
Methods
Length
Element access (get and set)
Elementwise addition
Printability (string conversion)
Skeleton
Note: unassigned string at start of class, method, or function is documentation
Access as class.__doc__ or func.__doc__
class SparseVec:
"""Implement sparse vector using index-to-value dictionary."""
__init__
__len__
__getitem__
__setitem__
__add__
__str__
Initialization and Length
def __init__(self, vals={}):
"""Construct new vector."""
self.val = {}
self.val.update(vals)
self.len = max([0] + vals.keys())
def __len__(self):
"Notional length of vector."""
return self.len
Getting and Setting Items
def __getitem__(self, i):
"""Get value at index, or 0."""
return self.val.get(i, 0.0)
def __setitem__(self, i, n):
"""Set value at index."""
self.val[i] = n
self.len = max(i, self.len)
Adding Vectors
def __add__(self, other):
"""Add two vectors."""
result = SparseVec()
for i in self.val:
result[i] = self[i] + other[i]
for j in other.val:
if j not in self.val:
result[j] = other[j]
return result
Converting to String
def __str__(self):
"""Convert vector to string."""
s = "["
if self.len > 0:
for i in range(self.len+1):
s += str(self[i])
if i < self.len:
s += ", "
s += "]"
return s
Testing
if __name__ == "__main__":
x = SparseVec({1:0.1, 3:0.3})
y = SparseVec({1:1.0, 2:2.0, 4:4.0})
print "x:", x
print "len(x):", len(x)
print "y:", y
print "x+y:", x+y
x[2] = 0.2
print "x is now:", x
print "y+x:", y+x
x: [0.0, 0.1, 0.0, 0.3]
len(x): 3
y: [0.0, 1.0, 2.0, 0.0, 4.0]
x+y: [0.0, 1.1, 2.0, 0.3, 4.0]
x is now: [0.0, 0.1, 0.2, 0.3]
y+x: [0.0, 1.1, 2.2, 0.3, 4.0]
$Id: pyobj.html,v 1.1.1.1 2004/01/04 05:02:31 reid Exp $