""" magicmethods.py Want to try out the examples? Don't want to type them up yourself? Never worry, magicmethods.py is a convenient Python module with all the class definitions for the examples in the magic methods guide in it. """ # FileObject class, demonstrating __init__ and __del__ from os.path import join class FileObject: """Wrapper for file objects to make sure the file gets closed on deletion.""" def __init__(self, filepath="~", filename="sample.txt"): # open a file filename in filepath in read and write mode self.file = open(join(filepath, filename), "r+") def __del__(self): self.file.close() del self.file # Word class, demonstrating __new__, comparisons class Word(str): """Class for words, defining comparison based on word length.""" def __new__(cls, word): # Note that we have to use __new__. This is because str is an immutable # type, so we have to initialize it early (at creation) if " " in word: print "Value contains spaces. Truncating to first space." word = word[:word.index(" ")] # Word is now all chars before first space return str.__new__(cls, word) def __gt__(self, other): return len(self) > len(other) def __lt__(self, other): return len(self) < len(other) def __ge__(self, other): return len(self) >= len(other) def __le__(self, other): return len(self) <= len(other) # AccessCounter class, demonstrating __setattr__, __getattr__, and __delattr__ class AccessCounter: """A class that contains a value and implements an access counter. The counter increments each time the value is changed.""" def __init__(self, val): self.__dict__["counter"] = 0 self.__dict__["value"] = val def __setattr__(self, name, value): if name == "value": self.__dict__["counter"] += 1 self.__dict__["value"] = value def __delattr__(self, name): if name == "value": self.__dict__["counter"] += 1 del self.__dict__["value"] # FunctionalList class, demonstrating __len__, __getitem__, __setitem__, __delitem__, # __iter__, and __reversed__ class FunctionalList: """A class wrapping a list with some extra functional magic, like head, tail, init, last, drop, and take.""" def __init__(self, values=None): if values is None: self.values = [] else: self.values = values def __len__(self): return len(self.values) def __getitem__(self, key): # if key is of invalid type or value, the list values will raise the error return self.values[key] def __setitem__(self, key, value): self.values[key] = value def __delitem__(self, key): del self.values[key] def __iter__(self): return iter(self.values) def __reversed__(self): return reversed(self.values) def append(self, value): self.values.append(value) def head(self): # get the first element return self.values[0] def tail(self): # get all elements after the first return self.values[1:] def init(self): # get elements up to the last return self.values[:-1] def last(self): # get last element return self.values[-1] def drop(self, n): # get all elements except first n return self.values[n:] def take(self, n): # get first n elements return self.values[:n] # Entity class demonstrating __call__ class Entity: """Class to represent an entity. Callable to update the entity"s position.""" def __init__(self, size, x, y): self.x, self.y = x, y self.size = size def __call__(self, x, y): """Change the position of the entity.""" self.x, self.y = x, y # snip... # Wrapper class to close an object in a with statement class Closer: """A context manager to automatically close an object with a close method in a with statement.""" def __init__(self, obj): self.obj = obj def __enter__(self): return self.obj # bound to target def __exit__(self, exception_type, exception_val, trace): try: self.obj.close() except AttributeError: # obj isn"t closable print "Not closable." return True # exception handled successfully # Classes to represent descriptors and their use class Meter(object): """Descriptor for a meter.""" def __init__(self, value=0.0): self.value = float(value) def __get__(self, instance, owner): return self.value def __set__(self, instance, value): self.value = float(value) class Foot(object): """Descriptor for a foot.""" def __get__(self, instance, owner): return instance.meter * 3.2808 def __set__(self, instance, value): instance.meter = float(value) / 3.2808 class Distance(object): """Class to represent distance holding two descriptors for feet and meters.""" meter = Meter() foot = Foot() # Class to demo fine-tuning pickling import time class Slate: """Class to store a string and a changelog, and forget its value when pickled.""" def __init__(self, value): self.value = value self.last_change = time.asctime() self.history = {} def change(self, new_value): # Change the value. Commit last value to history self.history[self.last_change] = self.value self.value = new_value self.last_change = time.asctime() def print_changes(self): print "Changelog for Slate object:" for k, v in self.history.items(): print "%s\t %s" % (k, v) def __getstate__(self): # Deliberately do not return self.value or self.last_change. # We want to have a "blank slate" when we unpickle. return self.history def __setstate__(self, state): # Make self.history = state and last_change and value undefined self.history = state self.value, self.last_change = None, None