As a bit of a learning project, I decided to take the concept of proxying objects a bit further and extend it to creating proxy classes which create proxy'd objects.  I originally found the idea of proxying objects in python on Activestate.  I'm currently using a very odd pattern (creating a class with just staticmethods and abusing __new__ to return my classes, instead of using a function (since that would reinstantiate __special_names__, __imethods__, and __other_magic__ every time it ran.Is this a good idea, or should I return to using a function that takes a type and returns a Proxy subclass?  On a second note, is there any way to make isinstance and issubclass happy without actually subclassing the given type?  I originally wanted to use __call__ for the class which would make it at least somewhat readable, since when you call functions, you call their __call__ attribute (afaik), but python seems to think I have to use the __new__ attribute instead to use a class as a function.The entire purpose of this class Proxy hack is to create Proxy classes for immutable objects - this way if you do a = b = 10 and a += 5, a == b == 15 without having to update b.Shameless self-plugging: This is actually a core piece of code at pyranoid, which I work on, since it seems interesting.import functoolsimport collectionsclass Proxy(type):    __special_names__ = {        '__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',        '__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__',        '__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__', '__getslice__',        '__gt__', '__hash__', '__hex__', '__int__', '__iter__', '__le__', '__len__',        '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__',        '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__',        '__rdivmod__', '__reduce__', '__reduce_ex__',  '__reversed__',        '__rfloorfiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__',        '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setitem__',        '__setslice__', '__sub__', '__truediv__', '__xor__', '__next__'    }    __imethods__ = {        '__iadd__', '__iand__', '__idiv__', '__idivmod__',        '__ifloordiv__', '__ilshift__', '__imod__', '__imul__',        '__invert__', '__ior__', '__ipow__', '__irshift__',        '__isub__', '__itruediv__', '__ixor__'    }    __other_magic__ = {        '__int__',        '__long__',        '__float__',        '__complex__',        '__oct__',        '__hex__',        '__index__',        '__trunc__',        '__coerce__',        '__str__',        '__repr__',        '__unicode__',        '__format__',        '__hash__',        '__nonzero__',        '__dir__',        '__sizeof__'    }    __overridden__ = __special_names__.union(__imethods__).union(__other_magic__)    @staticmethod    def __imethod_wrapper____(method):        '''makes a wrapper around __i<something>__ methods, such as __iadd__ to act on __subject__'''        @functools.wraps(method)        def wrapper(self,*args,**kwargs):            tmp = self.__subject__            tmp = method(tmp,*args,**kwargs)            self.__subject__ = tmp            return self        return wrapper    @staticmethod    def __method_wrapper__(method):        '''makes a wrapper around methods and cast the result to a proxytype if possible'''        @functools.wraps(method)        def wrapper(self,*args,**kwargs):            res = method(self.__subject__,*args,**kwargs)            try:                return Proxy(type(res),'Proxy<{t}>'.format(t=type(res).__name__))(res)            except TypeError: #if the result's type isn't subclassable, i.e. types.FunctionType would raise a TypeException                return res        return wrapper    @staticmethod    def usable_base_type(Type):        try:            type('',(Type,),{})            return True        except TypeError:            return False    def __new__(cls,parentType,classname=None): #So that Proxy emulates a function        '''parentType is the type you wish to proxy, and classname is the name that appears for the class, <class 'classname'>'''        if not cls.usable_base_type(parentType):            raise TypeError(type '{Type}' is not an acceptable base type.format(Type=parentType.__name__))        if classname is None:            classname = 'Proxy<{name}>'.format(name=parentType.__name__)        class newType(parentType):            def __init__(self,*args,**kwargs):                self.__subject__ = parentType(*args,**kwargs)            def setvalue(self,value):                self.__subject__ = value            def getvalue(self):                return self.__subject__            def __getattr__(self,name):                if name not in cls.__overridden__:                    return getattr(self.__subject__,name)        for name,prop in ((k,v) for k,v in parentType.__dict__.items() if k != '__doc__'): #because magic methods are implemented as staticmethods            if name in cls.__special_names__:                setattr(newType,name,cls.__method_wrapper__(prop))        for name in cls.__imethods__: #parentType may not implement all of them            if hasattr(parentType,name):                setattr(newType,name,cls.__imethod_wrapper____(parentType.__dict__[name]))            else:                non_i_name = name[:2]+name[3:]                if hasattr(parentType,non_i_name):                    setattr(newType,name,cls.__imethod_wrapper____(getattr(parentType,non_i_name)))        for name in cls.__other_magic__:            if hasattr(parentType,name):                parent_item = getattr(parentType,name)                if isinstance(parent_item,collections.Callable):                    setattr(newType,name,lambda self,*args,**kwargs:parent_item(self.__subject__,*args,**kwargs))                else:                    setattr(newType,name,parent_item)        newType.__name__ = classname        return newType
Creating Proxy classes for immutable objects
python;object oriented;immutability;proxy
Some quick thoughts:I can't tell from reading the code what the purpose is. What is this for? What are the use cases? How am I supposed to use it?There's no docstring for the Proxy class or for the usable_base_type method.What is the role of the Proxy class? You never seem to create any instances of it. (The __new__ method returns an instance of the newType that it has just created.) Python is not Java: not everything needs to be a class.Names starting and ending with two underscores are reserved for future use by the language and the standard library:__*__ System-defined names. These names are defined by the interpreter and its implementation (including the standard library). Current system names are discussed in the Special method names section and elsewhere. More will likely be defined in future versions of Python. Any use of __*__ names, in any context, that does not follow explicitly documented use, is subject to breakage without warning.So I'd recommend avoiding names of this form in your own code.What's the difference between __special_names__ and __other_magic__? Why is __slots__ not in either of these sets?The docstring for __method_wrapper__ says cast the result, but Python doesn't have casting. What does this method really do?Why does __imethod_wrapper____ end in four underscores?Instead of__special_names__.union(__imethods__).union(__other_magic__)you could write__special_names__ | __imethods__ | __other_magic____special_names__ is almost in alphabetical order (which is a useful way to order a list like this, because it helps you spot missing and duplicate items), but __next__ is out of order. Why is that?What order are the names in __other_magic__ in? Why not alphabetical order like the two other lists? And why is this list formatted with one name per line while the others are paragraph-wrapped?The method returned by __method_wrapper__ calls Proxy() each time it is called, which will create another newType class. Is this really what you want to happen? Won't this lead to a proliferation of identical classes?But really this is just fumbling in the dark because I don't understand what problem you are trying to solve. I see that you edited the post to add an explanation (you want to be able to proxy immutable objects), but this still leaves me in the dark. Why do you want to proxy immutable objects?