""" object_snoop allows user to observe how Python expressions and statements are translated into special method calls. object_snoop defines most special methods. It simple print a trace and returns a fixed but sensible result. Users are invited to build complex expressions to experiment how Python special methods work. Reference: Data model - Python v2.7 documentation http://docs.python.org/reference/datamodel.html """ import inspect class object_snoop(object): def __init__(self, name, truth=True): self.name = name self.truth = bool(truth) def __repr__(self): return '<%s>' % self.name # let __str__ and __unicode__ fallback to __repr__ def trace(self, *args, **kwargs): """ helper method to print ". [: ]" """ caller_frame = inspect.stack()[1] caller_name = caller_frame[3] _name, _caller = self.name, caller_name _colon = _args = _kwargs = "" if args or kwargs: _colon = ' :' if len(args) == 1: _args = ' ' + str(args[0]) elif args: _args = ' ' + str(args) if kwargs: _kwargs = ' ' + str(kwargs) print ("%(_name)s.%(_caller)s%(_colon)s%(_args)s%(_kwargs)s" % locals()) # ------------------------------------------------------------------------ # 1. Basic customization # Called when the instance is about to be destroyed def __del__(self): self.trace() # These are the so-called "rich comparison" methods, def __lt__(self, other): self.trace(other); return self.truth def __le__(self, other): self.trace(other); return self.truth def __eq__(self, other): self.trace(other); return self.truth def __ne__(self, other): self.trace(other); return self.truth def __gt__(self, other): self.trace(other); return self.truth def __ge__(self, other): self.trace(other); return self.truth # Called by comparison operations if rich comparison (see above) is not defined. def __cmp__(self, other): self.trace(other) return 1 # Called by built-in function hash() and for operations on members of hashed collections def __hash__(self): self.trace() return 1 # Called to implement truth value testing and the built-in operation bool() def __nonzero__(self): self.trace() return self.truth # ------------------------------------------------------------------------ # 2. Customizing attribute access def __getattr__(self, name): self.trace(name) return 1 def __setattr__(self, name, value): super(object_snoop,self).__setattr__(name, value) self.trace(name, value) def __delattr__(self, name): super(object_snoop,self).__delattr__(name) self.trace(name) # ------------------------------------------------------------------------ # 4. Customizing instance and subclass checks # ------------------------------------------------------------------------ # 5. Emulating callable objects def __call__(self, *args, **kwargs): self.trace(*args, **kwargs) # ------------------------------------------------------------------------ # 6. Emulating container types def __len__ (self): self.trace() ; return 1 def __getitem__ (self, key): self.trace(key) ; return 1 def __setitem__ (self, key, value): self.trace(key, value) def __delitem__ (self, key): self.trace(key) def __iter__ (self): self.trace() ; return iter([]) def __reversed__(self): self.trace() ; return iter([]) def __contains__(self, item): self.trace(item) ; return self.truth # ------------------------------------------------------------------------ # 7. Additional methods for emulation of sequence types # Deprecated since version 2.0 def __getslice__(self, i, j): self.trace(i,j) ; return self def __setslice__(self, i, j, sequence): self.trace(i,j,sequence) def __delslice__(self, i, j): self.trace(i,j) # ------------------------------------------------------------------------ # 8. Emulating numeric types # These methods are called to implement the binary arithmetic operations (+, # -, *, //, %, divmod(), pow(), **, <<, >>, &, ^, |). def __add__ (self, other): self.trace(other); return self def __sub__ (self, other): self.trace(other); return self def __mul__ (self, other): self.trace(other); return self def __floordiv__(self, other): self.trace(other); return self def __mod__ (self, other): self.trace(other); return self def __divmod__ (self, other): self.trace(other); return self def __pow__ (self, other): self.trace(other); return self def __lshift__ (self, other): self.trace(other); return self def __rshift__ (self, other): self.trace(other); return self def __and__ (self, other): self.trace(other); return self def __xor__ (self, other): self.trace(other); return self def __or__ (self, other): self.trace(other); return self def __div__ (self, other): self.trace(other); return self def __truediv__ (self, other): self.trace(other); return self # These methods are called to implement the binary arithmetic operations # with reflected (swapped) operands. def __radd__ (self, other): self.trace(other); return self def __rsub__ (self, other): self.trace(other); return self def __rmul__ (self, other): self.trace(other); return self def __rdiv__ (self, other): self.trace(other); return self def __rtruediv__ (self, other): self.trace(other); return self def __rfloordiv__(self, other): self.trace(other); return self def __rmod__ (self, other): self.trace(other); return self def __rdivmod__ (self, other): self.trace(other); return self def __rpow__ (self, other): self.trace(other); return self def __rlshift__ (self, other): self.trace(other); return self def __rrshift__ (self, other): self.trace(other); return self def __rand__ (self, other): self.trace(other); return self def __rxor__ (self, other): self.trace(other); return self def __ror__ (self, other): self.trace(other); return self # These methods are called to implement the augmented arithmetic assignments # (+=, -=, *=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=). def __iadd__ (self, other): self.trace(other); return self def __isub__ (self, other): self.trace(other); return self def __imul__ (self, other): self.trace(other); return self def __idiv__ (self, other): self.trace(other); return self def __itruediv__ (self, other): self.trace(other); return self def __ifloordiv__(self, other): self.trace(other); return self def __imod__ (self, other): self.trace(other); return self def __ipow__ (self, other): self.trace(other); return self def __ilshift__ (self, other): self.trace(other); return self def __irshift__ (self, other): self.trace(other); return self def __iand__ (self, other): self.trace(other); return self def __ixor__ (self, other): self.trace(other); return self def __ior__ (self, other): self.trace(other); return self # Called to implement the unary arithmetic operations (-, +, abs() and ~). def __neg__ (self): self.trace(); return self def __pos__ (self): self.trace(); return self def __abs__ (self): self.trace(); return self def __invert__(self): self.trace(); return self # Called to implement the built-in functions complex(), int(), long(), and float(), oct() and hex(). def __complex__(self): self.trace(); return 1 def __int__ (self): self.trace(); return 1 def __long__ (self): self.trace(); return 1 def __float__ (self): self.trace(); return 1.0 def __oct__ (self): self.trace(); return 'o' def __hex__ (self): self.trace(); return 'x' # Called to implement operator.index(). def __index__ (self): self.trace(); return self # Called to implement "mixed-mode" numeric arithmetic. def __coerce__(self, other): self.trace(other); return self # define two dummy objects. r evaluates to True and s evaluates to False. r = object_snoop('r', True) s = object_snoop('s', False)