therealmarv
therealmarv

Reputation: 3742

How to give a constant and a dynamic argument to functions which are stored in an array

I use an array for storage of functions which needs to be called in a row:

def do_xslt(xsl, xml):
    newxml = dosomethingwithit(xsl,xml)
    return newxml

TRANSFORM_PIPELINE = [
    do_xslt('pass1.xsl'),
    do_xslt('pass2.xsl'),
    do_xslt('pass3.xsl'),
]

what I now want to do is to call the TRANSFORM_PIPELINE with its given argument and a dynamic one.

I have something like this in my mind which should call in a loop do_xslt('passX.xsl', xml)

for transform in TRANSFORM_PIPELINE:
    xml = transform(xml) 

This approach is of course wrong. But how to make the right way in Python?

Upvotes: 1

Views: 98

Answers (2)

ThiefMaster
ThiefMaster

Reputation: 318488

Use functools.partial() to partially apply the function:

from functools import partial
TRANSFORM_PIPELINE = [
    partial(do_xslt, 'pass1.xsl'),
    partial(do_xslt, 'pass2.xsl'),
    partial(do_xslt, 'pass3.xsl')
]

Calling the functions returned by partial() will call do_xslt('pass1.xsl', *args, **kwargs) with *args and **kwargs being the arguments passed to the new function.

Demo:

>>> def do_xslt(xsl, xml):
...     print 'do_xslt(%r, %r)' % (xsl, xml)
...     return xml + '*' + xsl
...
>>> from functools import partial
>>> TRANSFORM_PIPELINE = [
...     partial(do_xslt, 'pass1.xsl'),
...     partial(do_xslt, 'pass2.xsl'),
...     partial(do_xslt, 'pass3.xsl')
... ]
>>> x = 'xml is lame'
>>> for transform in TRANSFORM_PIPELINE:
...     x = transform(x)
...     print x
...
do_xslt('pass1.xsl', 'xml is lame')
xml is lame*pass1.xsl
do_xslt('pass2.xsl', 'xml is lame*pass1.xsl')
xml is lame*pass1.xsl*pass2.xsl
do_xslt('pass3.xsl', 'xml is lame*pass1.xsl*pass2.xsl')
xml is lame*pass1.xsl*pass2.xsl*pass3.xsl

Upvotes: 2

spinlok
spinlok

Reputation: 3661

Use functools.partial() - http://docs.python.org/library/functools.html#functools.partial

TRANSFORM_PIPELINE = [
    functools.partial(do_xslt, 'pass1.xsl'),
    functools.partial(do_xslt, 'pass2.xsl'),
    functools.partial(do_xslt, 'pass3.xsl'),
]

Alternatively, you can also use a closure like so:

def do_xslt(xsl):
    def inner(xml):
        newxml = dosomethingwithit(xsl,xml)
        return newxml
    return inner

This way, you can keep the TRANSFORM_PIPELINE exactly the way you have it now.

Upvotes: 2

Related Questions