| prev | Version 1107 (Mon Nov 27 20:46:03 2006) | next |
__init__ and __str__obj has a __len__ method, Python calls it whenever it sees len(obj)class Recent(object):
def __init__(self, number=3):
self.number = number
self.items = []
def __str__(self):
return str(self.items)
def add(self, item):
self.items.append(item)
self.items = self.items[-self.number:]
def __len__(self):
return len(self.items)
if __name__ == '__main__':
history = Recent()
for era in ['Permian', 'Trassic', 'Jurassic', 'Cretaceous', 'Tertiary']:
history.add(era)
print len(history), history
1 ['Permian'] 2 ['Permian', 'Trassic'] 3 ['Permian', 'Trassic', 'Jurassic'] 3 ['Trassic', 'Jurassic', 'Cretaceous'] 3 ['Jurassic', 'Cretaceous', 'Tertiary']
"a + b" is “just” a shorthand for add(a, b)a is an object, for a.add(b)add, Python spells this method __add____add__, it is called whenever something is +'d to the objectx + y calls x.__add__(y)class Recent(object):
def __add__(self, item):
self.items.append(item)
self.items = self.items[-self.number:]
return self
if __name__ == '__main__':
history = Recent()
for era in ['Permian', 'Trassic', 'Jurassic', 'Cretaceous', 'Tertiary']:
history = history + era
print len(history), history
1 ['Permian'] 2 ['Permian', 'Trassic'] 3 ['Permian', 'Trassic', 'Jurassic'] 3 ['Trassic', 'Jurassic', 'Cretaceous'] 3 ['Jurassic', 'Cretaceous', 'Tertiary']
2 + x and x + 2 don't always do the same thing__radd__ instead of __add____add__ method, call that__radd__ method, call that| Method | Purpose |
|---|---|
__lt__(self, other) | Less than comparison; __le__, __ne__, and others are used for less than or equal, not equal, etc. |
__call__(self, args…) | Called for obj(3, "lithium") |
__len__(self) | Object “length” |
__getitem__(self, key) | Called for obj[3.14] |
__setitem__(self, key, value) | Called for obj[3.14] = 2.17 |
__contains__ | Called for "lithium" in obj |
__add__ | Called for obj + value; use __mul__ for obj * value, etc. |
__int__ | Called for int(obj); use __float__ and others to convert to other types |
| Table 15.1: Special Methods | |
v after the following operations?v = SparseVector() # all values initialized to 0.0 v[27] = 1.0 # length is now 28 v[43] = 1.0 # length is now 44 v[43] = 0.0 # is the length still 44, or 28?
__len__, __getitem__, and __setitem__ to make it behave like a listdel sparse[index]class SparseVector(object):
'''Implement a sparse vector. If a value has not been set
explicitly, its value is zero.'''
def __init__(self):
'''Construct a sparse vector with all zero entries.'''
self.data = {}
def __len__(self):
'''The length of a vector is one more than the largest index.'''
if self.data:
return 1 + max(self.data.keys())
return 0
def __getitem__(self, key):
'''Return an explicit value, or 0.0 if none has been set.'''
if key in self.data:
return self.data[key]
return 0.0
def __setitem__(self, key, value):
'''Assign a new value to a vector entry.'''
if type(key) is not int:
raise KeyError, 'non-integer index to sparse vector'
self.data[key] = value"*") is usually called other__rmul__ = __mul__ do the same thing as __rmul__ def __mul__(self, other):
'''Calculate dot product of a sparse vector with something else.'''
result = 0.0
for k in self.data:
result += self.data[k] * other[k]
return result
def __rmul__(self, other):
return self.__mul__(other) def __add__(self, other):
'''Add something to a sparse vector.'''
# Initialize result with all non-zero values from this vector.
result = SparseVector()
result.data.update(self.data)
# If the other object is also a sparse vector, add non-zero values.
if isinstance(other, SparseVector):
for k in other.data:
result[k] = result[k] + other[k]
# Otherwise, use brute force.
else:
for i in range(len(other)):
result[i] = result[i] + other[i]
return result
# Right-hand add does the same thing as left-hand add.
__radd__ = __add__print statements with assertionsif __name__ == '__main__':
x = SparseVector()
x[1] = 1.0
x[3] = 3.0
x[5] = 5.0
print 'len(x)', len(x)
for i in range(len(x)):
print '...', i, x[i]
y = SparseVector()
y[1] = 10.0
y[2] = 20.0
y[3] = 30.0
print 'x + y', x + y
print 'y + x', y + x
print 'x * y', x * y
print 'y * x', y * x
z = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
print 'x + z', x + z
print 'x * z', x * z
print 'z + x', z + x
len(x) 6 ... 0 0.0 ... 1 1.0 ... 2 0.0 ... 3 3.0 ... 4 0.0 ... 5 5.0 x + y [0.0, 11.0, 20.0, 33.0, 0.0, 5.0] y + x [0.0, 11.0, 20.0, 33.0, 0.0, 5.0] x * y 100.0 y * x 100.0 x + z [0.0, 1.1, 0.2, 3.3, 0.4, 5.5] x * z 3.5 z + x [0.0, 1.1, 0.2, 3.3, 0.4, 5.5]
class block belong to the class as a wholeclass Counter(object):
num = 0 # Number of Counter objects created.
def __init__(self, name):
Counter.num += 1
self.name = name
if __name__ == '__main__':
print 'initial count', Counter.num
first = Counter('first')
print 'after creating first object', Counter.num
second = Counter('second')
print 'after creating second object', Counter.num
initial count 0 after creating first object 1 after creating second object 2
self parameter@staticmethod in front of itclass Experiment(object):
already_done = {}
@staticmethod
def get_results(name, *params):
if name in Experiment.already_done:
return Experiment.already_done[name]
exp = Experiment(name, *params)
exp.run()
Experiment.already_done[name] = exp
return exp
def __init__(self, name, *params):
self.name = name
self.params = params
def run(self):
# marker:vdots
if __name__ == '__main__':
first = Experiment.get_results('anti-gravity')
second = Experiment.get_results('time travel')
third = Experiment.get_results('anti-gravity')
print 'first ', id(first)
print 'second', id(second)
print 'third ', id(third)
first 5120204 second 5120396 third 5120204
class AntennaClass(object):
'''Singleton that controls a radio telescope.'''
# The unique instance of the class.
instance = None
# The constructor fails if an instance already exists.
def __init__(self, max_rotation):
assert AntennaClass.instance is None, 'Trying to create a second instance!'
self.max_rotation = max_rotation
AntennaClass.instance = self
# Make the creation function look like a class constructor.
def Antenna(max_rotation):
'''Create and store an AntennaClass instance, or return the one
that has already been created.'''
if AntennaClass.instance:
return AntennaClass.instance
return AntennaClass(max_rotation)first = Antenna(23.5) print 'first instance:', id(first) second = Antenna(47.25) print 'second instance:', id(second)
first instance: 10685200 second instance: 10685200
class NestedListVisitor(object):
'''Visit each element in a list of nested lists.'''
def __init__(self, data):
'''Construct, but do not run.'''
assert type(data) is list, 'Only works on lists!'
self.data = data
def run(self):
'''Iterate over all values.'''
self.recurse(self.data)
def recurse(self, current):
'''Loop over a particular list or sub-list (not meant
to be called by users).'''
if type(current) is list:
for v in current:
self.recurse(v)
else:
self.visit(current)
def visit(self, value):
'''Users should fill this method in.'''
passclass MaxOfN(NestedListVisitor):
def __init__(self, data):
NestedListVisitor.__init__(self, data)
self.max = None
self.count = 0
def visit(self, value):
self.count += 1
if self.max is None:
self.max = value
else:
self.max = max(self.max, value)
test_data = [['gold', 'lead'], 'zinc', [['silver', 'iron'], 'mercury']]
test = MaxOfN(test_data)
test.run()
print 'max:', test.max
print 'count:', test.count
max: zinc count: 6
![[]](./img/oop02/factory_type_family.png)
Figure .:
class AbstractFamily(object):
'''Builders for particular families derive from this.'''
def __init__(self, family):
self.family = family
def get_name(self):
return self.name
def make_controller(self):
raise NotImplementedError('make_controller missing')
def make_configuration_panel(self):
raise NotImplementedError('make_configuration_panel missing')class FactoryManager(object):
'''Manage builders by family.'''
def __init__(self, current_family=None):
self.builders = {}
self.family = family
def set_family(self, family):
assert family, 'Empty family'
self.family = family
def add(self, builder):
name = builder.get_name()
self.builders[name] = builder
def make_controller(self):
self._check_state()
return self.builders[self.family].make_controller()
def make_configuration_panel(self):
self._check_state()
return self.builders[self.family].make_configuration_panel()
def _check_state(self):
assert self.family, 'No family specified'
assert self.family in self.builders, 'Unknown family:', self.familyfactory = FactoryManager()
factory.add(RCT100Factory())
factory.add(Subalta4CFactory())
factory.set_family('Subalta4C')
controller = factory.make_controller()
configuration_panel = factory.make_configuration_panel()do, undo, and redo methodsclass AbstractCommand(object):
'''Base class for commands.'''
def is_undoable(self):
return False # by default, can't undo/redo operations
def do(self, robot):
raise NotImplementedError("Don't know how to do %s" % self.name)
def undo(self, robot):
pass
def redo(self, robot):
passclass MoveCommand(AbstractCommand):
'''Move the robot arm.'''
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def is_undoable(self):
return True
def do(self, robot):
robot.translate(self.x, self.y, self.z)
def undo(self, robot):
robot.translate(-self.x, -self.y, -self.z)
def redo(self, robot):
self.do(robot)robot = Robot()
commands = [MoveCommand(5.0, 2.0, 2.3),
RotateCommand(-90.0, 0.0, 0.0),
MoveCommand(1.0, 2.0, 2.0),
CloseHandCommand()]
for c in commands:
c.do(robot)| prev | Copyright © 2005-06 Python Software Foundation. | next |