Author alonho
Recipients Alexander.Belopolsky, Christophe Simonis, alonho, anacrolix, belopolsky, eckhardt, ironfroggy, jackdied, jcea, ncoghlan, r.david.murray, rhettinger, ssadler
Date 2013-10-27.12:17:03
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1382876223.6.0.449322219197.issue4331@psf.upfronthosting.co.za>
In-reply-to
Content
I think the following test demonstrates the API we're looking for.
1. Am I missing any functionality?
2. How does partialmethod relate to @absolutemethod?

from functools import partial

class partialmethod(object):

    def __init__(self, func, *args, **keywords):
        # func could be a descriptor like classmethod which isn't callable,
        # so we can't inherit from partial (it verifies func is callable)
        if isinstance(func, partialmethod):
            # flattening is mandatory in order to place cls/self before all other arguments
            # it's also more efficient since only one function will be called
            self.func = func.func
            self.args = func.args + args
            self.keywords = {}
            self.keywords.update(func.keywords)
            self.keywords.update(keywords)
        else:
            self.func = func
            self.args = args
            self.keywords = keywords
    
    def _make_unbound_method(self):
        def _method(*args, **keywords):
            keywords.update(self.keywords)
            cls_or_self, *rest = args
            call_args = (cls_or_self,) + self.args + tuple(rest)
            return self.func(*call_args, **keywords)
        return _method

    def __get__(self, obj, cls):
        get = getattr(self.func, "__get__", None)
        if get is None:
            if obj is None:
                return self._make_unbound_method()
            return partial(self._make_unbound_method(), obj) # returns a bound method
        else:
            callable = get(obj, cls)
            if callable is self.func:
                return self._make_unbound_method()
        return partial(callable, *self.args, **self.keywords)

class A(object):
    def add(self, x, y):
        return self, x + y

    add10 = partialmethod(add, 10)
    add10class = partialmethod(classmethod(add), 10)
    add10static = partialmethod(staticmethod(add), 'self', 10)

    return15 = partialmethod(add10, 5) # nested partialmethod
    
    add2partial = partial(add, x=2)
    return12 = partialmethod(add2partial, y=10) # partialmethod over partial
    
def test():
    cls = A
    instance = cls()

    assert instance.add10class(5) == (cls, 15)
    assert cls.add10class(5) == (cls, 15)

    assert instance.add10static(5) == ('self', 15)
    assert cls.add10static(5) == ('self', 15)
    
    assert instance.add10(5) == (instance, 15)
    assert cls.add10(instance, 5) == (instance, 15)
    
    assert instance.return15() == (instance, 15)
    assert cls.return15(instance) == (instance, 15)

    assert instance.return12() == (instance, 12)
    assert cls.return12(instance) == (instance, 12)

test()
History
Date User Action Args
2013-10-27 12:17:03alonhosetrecipients: + alonho, rhettinger, jcea, ncoghlan, belopolsky, ironfroggy, jackdied, Christophe Simonis, ssadler, eckhardt, r.david.murray, Alexander.Belopolsky, anacrolix
2013-10-27 12:17:03alonhosetmessageid: <1382876223.6.0.449322219197.issue4331@psf.upfronthosting.co.za>
2013-10-27 12:17:03alonholinkissue4331 messages
2013-10-27 12:17:03alonhocreate