a (useful???) curiosity inspired by monty python, guido's multimethods demo, and schizophrenia.
comments to: photon DOT thug AT gmail DOT com
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.