Using closures and partial functions to eliminate redundant code

Matthew Wilson matt at tplus1.com
Wed Sep 26 22:01:17 EDT 2007


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



More information about the Python-list mailing list