Welcome, guest | Sign In | My Account | Store | Cart

a (useful???) curiosity inspired by monty python, guido's multimethods demo, and schizophrenia.

comments to: photon DOT thug AT gmail DOT com

Python, 116 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
###############################################################################

import inspect, new, sys

registry = {}

# master registry for methodnames, decorators, and proxy scope dummy object
###############################################################################

class proxy(object): pass

def personalityDependant(func):
   """ we have to save func in the registry so each duplicate 
            function name doesnt just overwrite the previous one 
   
            NOTE: "whichSelf" is the name of the variable used where 
                  "self" is usually found in instancemethod definitions
   """
   whichSelf = inspect.getargspec(func)[0][0]  
   if whichSelf not in registry:	registry[whichSelf] = {}
   registry[whichSelf][func.__name__] = func		
   return func	

def schizophrenic(func):
   """ tag a function as schizophrenic so the metaclass knows when to 
      effect the scope mangling. """
   func.schizophrenic=True
   return func

# metaclass for all schizoids
###############################################################################

class schizotypal(type):		
   """ """
   @staticmethod
   def __new__(mcls, name, bases, clsdict):
      err1 ='expected a schizotypal object would have a list of personalities.'
      try:			assert 'personalities' in clsdict
      except AssertionError:	raise Exception, err1
      else:			
            personalities = clsdict['personalities']
            replacement   = {}
            for pName in personalities: replacement[pName] = registry[pName]
            personalities = replacement
            clsdict['personalities'] = personalities
            klassobj = type.__new__(mcls, name, bases, clsdict)
      return klassobj
	
   def __call__(cls, *args, **kargs):
      inst = type.__call__(cls, *args, **kargs)
      for var in dir(inst):
            val  = getattr(inst, var)
            test = var!='__metaclass__' and var!='__class__'
            if hasattr(val, 'schizophrenic') and test:
               for pName in inst.personalities:
                        val.func_globals[pName] = inst.as(pName)
      return inst

# base schizoid object (inherit from this)
###############################################################################

class schizoid(object):
   """ """		
   __metaclass__ = schizotypal
   personalities = []
   
   def as(self, pName):
      """ obtain a representation of self with respect to some personality """
      cls = self.__class__
      err = 'illegal personality for '+str(cls) + ': ' + pName
      assert pName in cls.personalities, err
      out   = cls.personalities[pName]
      P = proxy()
      for funcname in out:
            func = out[funcname]
            func = new.instancemethod(func,self,cls)
            setattr(P, funcname, func)
      return P
			
# a demo
###############################################################################

class myschizoid(schizoid):		
   """ a simple demo.

      note that without the decorators, each status() definition would simply
      overwrite the previous one.  notice also under normal python semantics
      how theres no reason the philosopher names in the run() method should 
      be in scope.
   """
   personalities = ['kant','heidegger','wittgenstein','schlegel']
   
   @personalityDependant
   def status(kant):          return "a real pissant"
   
   @personalityDependant 
   def status(heidegger):     return "a boozy beggar" 
   
   @personalityDependant 
   def status(wittgenstein):  return "beery swine"
   
   @personalityDependant 
   def status(schlegel):      return "schloshed"
   
   @schizophrenic
   def run(self):
      print
      print 'kant:\t\t\t',		kant.status()
      print 'heidegger:\t\t',		heidegger.status()
      print 'wittgenstein:\t\t',	wittgenstein.status()
      print 'schlegel:\t\t',		schlegel.status()
      print

if __name__=='__main__':		
	s = myschizoid()
	s.run()

What we have here is a kind of bizarre idiom where how an object behaves depends on what you call it. It is perhaps similar in spirit to what the rejected roles pep might have accomplished.

I find I need something like this quite often, and I'm still experimenting with different ways of achieving it.. I'm very curious to know if people think this is interesting or a total abomination.

It's pretty easy to imagine extensions, like where the data you look at is also "perspective oriented", ie two different kinds of people look at the same distance, but one sees yards and another sees meters, etc.

Created by photon thug on Fri, 2 Nov 2007 (PSF)
Python recipes (4591)
photon thug's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks