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 thatMethod | 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.''' pass
class 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
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.family
factory = 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): pass
class 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 |