Pass-by-reference : Could a C#-like approach work in Python?

Peter Otten __peter__ at web.de
Fri Sep 12 00:57:10 CEST 2003


Michael Chermside wrote:

>>> if copying is costly and only
>> sometimes necessary, wrap the item into a copy-on-write proxy for every
>> logically distinct but physically identical instance.
> 
> Excellent idea! But, how do I write a copy-on-write proxy in Python?
> Seems like this would make an excellent cookbook recipie, but I couldn't
> figure out how to do it. Proxying is easy, but how does one distinguish
> between mutating and non-mutating methods? Does the proxy need to be
> customized for each class to be wrapped?
> 

I have to admit that the generic copy-on-write proxy is still vaporware :-(
However, I've come up with a way to make a class its own proxy, with
relatively small overhead and no need for advanced stuff like metaclasses
(which I have yet to master).

class COW(object):
    def __init__(self, template=None):
        self._template = template
    def __getattribute__(self, name):
        try:
            return object.__getattribute__(self, name)
        except AttributeError:
            return getattr(self._template, name)
    def __str__(self):
        return "--%s---\n" % self._name + "\n".join(["%s = %r" % (n,      
            getattr(self, n)) for n in "a b".split()])
    def proxy(self):
        return COW(self)

def printBoth():
    print "%s\n\n%s\n---\n" % (o1, o2)

o1 = COW()
o1.a = "default A"
o1.b = "default B"
o1._name = "Obj1"

o2 = o1.proxy() # same as o2 = COW(o1)
o2._name = "Obj2"
printBoth()

o1.a = "override" # seen in both o1 and o2
printBoth()

o2.a = "shade" # hides o1.a
printBoth()

del o2.a # o1.a visible again
printBoth()

print o2.nonExistent # misleading error message

All methods are identical for proxy and original by design. Attributes are
rather shaded than copied, and thus there is no need to copy the whole
attribute set if two instances differ only in a single attribute.
The overhead in the class definition is not that large: one method plus one
attribute.

There are some loose ends:
- Should mutable attributes be recursively proxied?
- How does the above behave in an inheritance tree?
- Performance may suffer as the "proxy chain" grows
- I've got a hunch that one could come up with an even more general/less
intrusive solution using metaclasses

Always-speculatingly yours,
Peter




More information about the Python-list mailing list