Using closures and partial functions to eliminate redundant code
Paul McGuire
ptmcg at austin.rr.com
Wed Sep 26 22:20:49 EDT 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