define

Duncan Booth duncan at NOSPAMrcp.co.uk
Tue May 13 04:58:31 EDT 2003


bokr at oz.net (Bengt Richter) wrote in news:b9ohig$i07$0 at 216.39.172.122:

>>I would probably write the former as:
>>
>>(a, b, c, sign) = (self.a, self.b, self.c, self.sign)
>>self.y = (-b + sign*sqrt(b**2 - 4.0*a*c))/2.0*a
>>
>>Maybe the present request could be satisfied by finding a way to simplify
>>the compound assignment?
>>
> Hm, ...
> 
>     (a, b, c, sign) = self.(a, b, c, sign)
>     self.y = (-b + sign*sqrt(b**2 - 4.0*a*c))/2.0*a
> 
> ??

Let's not forget that Python does have a builtin macro processor, called 
Python. Here, by adding a lot of code, is one way to completely hide the 
assignment from self. 

Health warning: read from the bottom up, the bit of interest is the 'class 
C'. Or maybe don't read at all.

The metaclass version of this is left as an exercise for Alex. :-)

---- test.py ----
import inspect, sys
from math import sqrt

def mkwrapper(fn, nArgs = sys.maxint-1):
    argnames, positional, keyword = inspect.getargs(fn.func_code)
    if argnames:
        selfname = argnames[0]
    wrappedargs = argnames[1:nArgs+1]
    unwrapped = argnames[:1] + argnames[nArgs+1:]
    
    wrappedcall = (argnames[:1] +
        [ "%s.%s" % (selfname, arg) for arg in wrappedargs ] +
        argnames[nArgs+1:])

    if positional:
        unwrapped += ["*" + positional]
        wrappedcall += ["*" + positional]
    if keyword:
        unwrapped += ["**" + keyword]
        wrappedcall += ["**" + keyword]

    commasep = ", ".join
    return fn.func_name, commasep(unwrapped), commasep(wrappedcall)

def argsFromSelf(fn, nArgs=sys.maxint-1):
    '''argsFromSelf(fn, [nArgs])
    Create a new function which calls the original but takes
    some or all arguments as attributes of the first argument.

    e.g.
        def fn(self, x, y, z):
            ...
        fn = argsFromSelf(fn, 2)

    is (roughly) equivalent to:
        def fn(self, z):
            x, y = self.x, self.y
            ...
    '''
    name, argsin, argsout = mkwrapper(fn, nArgs)
    code = '''\
def wrapit(fn):
    def %s(%s):
        return fn(%s)
    return %s
''' % (name, argsin, argsout, name)
    namespace = {}
    exec code in globals(), namespace
    return namespace['wrapit'](fn)

import unittest

class TestWrapper(unittest.TestCase):
    def testNoArgs(self):
        def f(): pass
        self.assertEquals(mkwrapper(f),
            ('f', '', ''))

    def testSelfOnly(self):
        def f(slf): pass
        self.assertEquals(mkwrapper(f),
            ('f', 'slf', 'slf'))

    def testOneArg(self):
        def f(slf, arg1): pass
        self.assertEquals(mkwrapper(f),
            ('f', 'slf', 'slf, slf.arg1'))
        
    def testSeveral(self):
        def f(slf, arg1, arg2, arg3): pass
        self.assertEquals(mkwrapper(f),
            ('f', 'slf', 'slf, slf.arg1, slf.arg2, slf.arg3'))
        self.assertEquals(mkwrapper(f, 1),
            ('f', 'slf, arg2, arg3', 'slf, slf.arg1, arg2, arg3'))

    def testpositional(self):
        def g(self, arg1, *args): pass
        self.assertEquals(mkwrapper(g),
            ('g', 'self, *args', 'self, self.arg1, *args'))

    def testkw(self):
        def g(self, arg1, **kw): pass
        self.assertEquals(mkwrapper(g),
            ('g', 'self, **kw', 'self, self.arg1, **kw'))

    def testInClass(self):
        class C:
            def __init__(self, a, b, c, sign):
                self.a, self.b, self.c, self.sign = a, b, c, sign

            def root(self, a, b, c, sign):
                return (-b + sign*sqrt(b**2 - 4.0*a*c))/(2.0*a)

            # def root1(self, sign): ...
            root1 = argsFromSelf(root, nArgs = 3)

            # def root(self): ...
            root = argsFromSelf(root)


        inst = C(1, 4, 3, 1)
        self.assertEquals(inst.root(), -1.0)
        self.assertEquals(inst.root1(sign=1), -1.0)
        self.assertEquals(inst.root1(-1), -3.0)

if __name__=='__main__':
    unittest.main()

-----------------
-- 
Duncan Booth                                             duncan at rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?




More information about the Python-list mailing list