Using closures and partial functions to eliminate redundant code

timaranz at gmail.com timaranz at gmail.com
Wed Sep 26 23:16:56 EDT 2007


On Sep 27, 2: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

Without using partials, I would do something like

def _create_or_update_user(mode, username, userpassword, useremail)
   blah, blah, blah

def update_user(username, userpassword, useremail):
   'update doc string'
   return _create_or_update_user('update', username, userpassword,
useremail)

def create_user(username, userpassword, useremail):
   'create doc string'
   return _create_or_update_user('create', username, userpassword,
useremail)

Cheers
Tim




More information about the Python-list mailing list