On 23/11/2013 19:53, Rotwang wrote:
[...]

That's pretty cool. However, I can imagine it would be nice for the
chained object to still be an instance of its original type. How about
something like this:

[crap code]

The above code isn't very good - it will only work on types whose
constructor will copy an instance, and it discards the original. And its
dir() is useless. Can anyone suggest something better?

Here's another attempt:

class dummy:
    pass

def initr(self, obj):
    super(type(self), self).__setattr__('__obj', obj)
def getr(self, name):
    try:
        return super(type(self), self).__getattribute__(name)
    except AttributeError:
        return getattr(self.__obj, name)
def methr(method):
    def selfie(self, *args, **kwargs):
        result = method(self.__obj, *args, **kwargs)
        return self if result is None else result
    return selfie

class chained(type):
    typedict = {}
    def __new__(cls, obj):
        if type(obj) not in cls.typedict:
            dict = {}
            for t in reversed(type(obj).__mro__):
                dict.update({k: methr(v) for k, v in t.__dict__.items()
                            if callable(v) and k != '__new__'})
            dict.update({'__init__': initr, '__getattribute__': getr})
            cls.typedict[type(obj)] = type.__new__(cls, 'chained%s'
                % type(obj).__name__, (dummy, type(obj)), dict)
        return cls.typedict[type(obj)](obj)


This solves some of the problems in my earlier effort. It keeps a copy of the original object, while leaving its interface pretty much unchanged; e.g. repr does what it's supposed to, and getting or setting an attribute of the chained object gets or sets the corresponding attribute of the original. It won't work on classes with properties, though, nor on classes with callable attributes that aren't methods (for example, a class with an attribute which is another class).
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to