Using closures and partial functions to eliminate redundant code

Paul McGuire ptmcg at austin.rr.com
Thu Sep 27 04:20:49 CEST 2007


On Sep 26, 9:01 pm, Matthew Wilson <m... at tplus1.com> wrote:
> I wrote some code to create a user and update a user on a remote box by
> sending emails to that remote box.  When I was done, I realized that my
> create_user function and my update_user function were effectively
> identical except for different docstrings and a single different value
> inside:
>
>     ### VERSION ONE
>
>     def create_user(username, userpassword, useremail):
>         "Send an email that will create a user in the remote system."
>
>         # Build email
>         email_body = """
>     USERNAME = %s
>     USERPASSWORD = %s
>     USEREMAIL = %s
>     """ % (username, userpassword, useremail)
>
>         # send it.
>         send_email(subject="CREATE", body=email_body)
>
>     def update_user(username, userpassword, useremail):
>         "Send an email that will update a user's password in the remote system."
>
>         # Build email
>         email_body = """
>     USERNAME = %s
>     USERPASSWORD = %s
>     USEREMAIL = %s
>     """ % (username, userpassword, useremail)
>
>         # send it.
>         send_email(subject="UPDATE", body=email_body)
>
>     ### END
>
> Then I came up with this approach to avoid all that redundant text:
>
>     ### VERSION TWO
>
>     def _f(mode):
>
>         if mode not in ("create", "update"):
>             raise ValueError("mode must be create or update!")
>
>         def _g(username, userpassword, useremail):
>
>             # Build email
>             email_body = """
>         USERNAME = %s
>         USERPASSWORD = %s
>         USEREMAIL = %s
>         """ % (username, userpassword, useremail)
>
>             # send it.  
>             send_email(subject=mode.upper(), body=email_body)
>
>         # Seems goofy, but other ways are there?
>
>         docstrings = {'create': "Send an email that will create a user in the remote system.",
>                       'update': "Send an email that will update a user's password in the remote system."}
>
>         _g.__doc__ = docstrings[mode]
>
>         return _g
>
>     # Then I created my functions like this:
>
>     v2_create_user = _f("create")
>     v2_update_user = _f("update")
>
>     ### END
>
> Finally, I came up with this approach:
>
>     ### VERSION THREE
>
>     from functools import partial
>
>     def _h(mode, username, userpassword, useremail):
>
>         if mode not in ("create", "update"):
>             raise ValueError("mode must be create or update!")
>
>         # Build email
>         email_body = """
>     USERNAME = %s
>     USERPASSWORD = %s
>     USEREMAIL = %s
>     """ % (username, userpassword, useremail)
>
>         # send it.  
>         send_email(subject=mode.upper(), body=email_body)
>
>     # I can't figure out how to set up the docstring on these.
>
>     v3_create_user = partial(_h, mode="create")
>     v3_update_user = partial(_h, mode="update")
>
>     ### END
>
> I'm interested to hear how other people deal with really similar code.
> The similarity just bugs me.  However, I wonder if using stuff like
> closures or partial function application is needlessly showy.
>
> Also, I hope anyone here can help me figure out how to attach a
> meaningful docstring for my version three code.
>
> Thanks in advance!
>
> Matt

Haven't used partial yet, but I'm very interested.  Of course, I think
this will work just as well:

def make_method(mode,docstring):
    def _inner(username, userpassword, useremail):
        # implementation of common routine code goes here
        # note: no need to clutter arg list with 'mode' now
    _inner.__name__ = mode + "_user"
    _inner.__doc__ = docstring
    return _inner

Does this not work?

    v3_create_user = partial(_h, mode="create")
    v3_create_user.__doc__ = "Send an email that will create a user in
the remote system."
    v3_update_user = partial(_h, mode="update")
    v3_update_user.__doc__ = "Send an email that will update a user's
password in the remote system."


-- Paul




More information about the Python-list mailing list