471,354 Members | 1,751 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,354 software developers and data experts.

Using closures and partial functions to eliminate redundant code

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
Sep 27 '07 #1
5 1460
On Sep 26, 9:01 pm, Matthew Wilson <m...@tplus1.comwrote:
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

Sep 27 '07 #2
On Sep 27, 2:01 pm, Matthew Wilson <m...@tplus1.comwrote:
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

Sep 27 '07 #3
En Wed, 26 Sep 2007 23:01:17 -0300, Matthew Wilson <ma**@tplus1.com>
escribi�:
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:
I would have used an object with two methods... But this is just another
example of the closure/object dichotomy. Some enlightment:
http://people.csail.mit.edu/gregs/ll.../msg03277.html

--
Gabriel Genellina

Sep 27 '07 #4
Matthew Wilson a écrit :
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
(snip)
>
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.
Depends.
The similarity just bugs me. However, I wonder if using stuff like
closures or partial function application is needlessly showy.
Not necessarily, but in this case, it's just overkill IMHO - I'd just
have factored out the common code:

def _build_email(username, userpassword, useremail):
""" builds the email body used by create_uer and update_user """
return """
USERNAME = %s
USERPASSWORD = %s
USEREMAIL = %s
""" % (username, userpassword, useremail)
def create_user(username, userpassword, useremail):
"Send an email that will create a user in the remote system."
send_email(subject="CREATE",
body=_build_email(username, userpassword, useremail)
)
def update_user(username, userpassword, useremail):
"Send an email that will update a user's password in the remote
system."
send_email(subject="UPDATE",
body=_build_email(username, userpassword, useremail)
)

Now there are of course cases where either closures and/or partials are
the right thing to do.
Also, I hope anyone here can help me figure out how to attach a
meaningful docstring for my version three code.
Didn't try, but what about:
p = partial(func, arg)
p.__doc__ = "yadda yadda"

Sep 27 '07 #5
Matthew Wilson wrote:
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.
ACK -- but not because it's showy, but because it may be more
error-prone and less readable. I'd often use an approach like this:

def create_user(username, userpassword, useremail, create = False):
"""
Send an email that will update a user in the remote system.
If create evaluates to True, don't update the user, but create
her instead.
"""
if not create:
subject = "UPDATE"
else:
subject = "CREATE"

# Build email
email_body = """
USERNAME = %s
USERPASSWORD = %s
USEREMAIL = %s
""" % (username, userpassword, useremail)
# send it.
send_email(subject=subject, body=email_body)

Regards,
Björn

--
BOFH excuse #353:

Second-system effect.

Sep 27 '07 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by paolo veronelli | last post: by
28 posts views Thread by Daniel | last post: by
6 posts views Thread by Joe Kelsey | last post: by
21 posts views Thread by Rubén Campos | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.