classification
Title: Add custom __repr__ to functools.partial
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.2
process
Status: closed Resolution: accepted
Dependencies: Superseder:
Assigned To: belopolsky Nosy List: belopolsky, daniel.urban, eric.araujo, georg.brandl, lemburg, rhettinger, stribb, terry.reedy, thomaslee
Priority: low Keywords: easy, patch

Created on 2008-10-13 11:45 by stribb, last changed 2010-12-01 20:36 by belopolsky. This issue is now closed.

Files
File name Uploaded Description Edit
issue4113-01.patch thomaslee, 2008-10-19 14:58 Patch for issue 4113, revision 1
issue4113.diff daniel.urban, 2010-11-19 14:47 Patch (py3k branch)
issue4113b.diff daniel.urban, 2010-11-19 21:20 Patch 2 (py3k branch)
Messages (15)
msg74682 - (view) Author: Andrew Stribblehill (stribb) Date: 2008-10-13 11:45
When I partially apply a function using functools.partial(), the
resultant function doesn't have the same name as the original function
(it has no __name__) and its docstring is that of functools.partial()
rather than that of the function that was partially applied.

Transcript:

Python 2.6 (r26:66714, Oct 13 2008, 10:32:02)
[GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>> import functools
>>> def sum(a,b,c):
...   return a+b+c
...
>>> functools.partial(sum,1)
<functools.partial object at 0xf7efeb6c>
>>> p = functools.partial(sum, 1)
>>> p.__name__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'functools.partial' object has no attribute '__name__'
>>> p(2,3)
6
>>> sum.__name__
'sum'
>>> sum.__doc__
>>> p.__doc__
'partial(func, *args, **keywords) - new function with partial
application\n\tof the given arguments and keywords.\n'
msg74945 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2008-10-17 22:45
Same in 3.0
msg74977 - (view) Author: Thomas Lee (thomaslee) (Python committer) Date: 2008-10-19 14:58
Here's a patch against the 2.x trunk. Basically just dispatches reads of
a partial's __name__ and __doc__ attributes to the underlying function
object.
msg74982 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2008-10-19 20:38
I do not think the partial object should have the original function's
__name__ or __doc__. It is after all not that function, but a callable
that calls it. (This is different from e.g. a decorated function -- the
decorator is taken as "modifying the function", even if it returns a
wholly different one. This is why functools.wraps() exists.)

In any case, this is not a bug but a feature request.
msg74986 - (view) Author: Thomas Lee (thomaslee) (Python committer) Date: 2008-10-20 02:23
I actually agree with the sentiment Georg.

Would it instead be useful to maybe provide a __repr__ implementation
that describes the state of the partially applied function? I guess this
is an entirely different issue, maybe one for python-ideas.
msg107504 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2010-06-11 00:01
I understand that the latest RFE in this issue is to provide a custom __repr__ to functools.partial.  Something along the lines of

class partial(functools.partial):
    def __repr__(self):
        return "functools.partial(%r, %s)" % (self.func, 
                      ', '.join(repr(a) for a in self.args)


>>> def f(x, y, z):
...   pass
>>> partial(f, 1, 2)
functools.partial(<function f at 0x10065b060>, 1, 2)

Looks like a reasonable proposal, but coding this in C is a chore. (The prototype above does not process keywords, so complete implementation is more involved.)
msg121417 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2010-11-18 02:12
One function in inspect can do everything we want, only not in C.  How hard/inefficient would it be to have 99% of partial coded in C and one stub in functools.py?
msg121449 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2010-11-18 09:54
> Looks like a reasonable proposal, but coding this in C is a chore. 

It's not that bad.  Most C code is a bit of a chore compared to Python but it really doesn't take much to write a C equivalent of: "functools.partial(%r, %s)" % (self.func, ', '.join(repr(a) for a in self.args)

>  How hard/inefficient would it be to have 99% of partial 
> coded in C and one stub in functools.py?

Let's not do this.  There is too little benefit to warrant going down the path of splitting the code across two langauges.
msg121525 - (view) Author: Daniel Urban (daniel.urban) * (Python triager) Date: 2010-11-19 14:47
Here is a patch. It includes tests.
msg121533 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2010-11-19 15:23
There is an ongoing discussion about deprecating undocumented PyUnicode_AppendAndDel(). See Marc-Andre's comment in msg121371:

"""
+.. c:function:: void PyUnicode_Append(PyObject **pleft, PyObject *right)
+
+   Concat two strings and put the result in *pleft. Sets *pleft to
+   NULL on error.
+
+.. c:function:: void PyUnicode_AppendAndDel(PyObject **pleft, PyObject *right)
+
+   Concat two strings and put the result in *pleft and drop the right
+   object. Sets *pleft to NULL on error.
+
+

Please don't document these two obscure APIs. Instead we should
make them private functions by prepending them with an underscore.
If you look at the implementations of those two APIs, they
are little more than a macros around PyUnicode_Concat().

3rd party extensions should use PyUnicode_Concat() to achieve
the same effect.
"""

While it is OK for Python library to use private APIs, please consider if PyUnicode_Concat() may be more appropriate.  If not, please make a case at issue 10435 for keeping it public.
msg121569 - (view) Author: Daniel Urban (daniel.urban) * (Python triager) Date: 2010-11-19 21:20
Well, of course it can be done with PyUnicode_Concat (obviously, since PyUnicode_AppendAndDel uses that). I used PyUnicode_AppendAndDel because that function does exactly what I needed.

I don't see why PyUnicode_AppendAndDel should be deprecated. Anyway, here is a new patch which uses PyUnicode_Concat.
msg123006 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2010-12-01 20:07
I simplified the partial_repr() code in issue4113b.diff and committed as r86916.

I wonder, however, if for the common case of func being a named function, displaying func.__name__ or func.__module__ + '.' + func.__name__ in repr(partial) may be more apropriate than repr(f).

For example, 

functools.partial(f, 1, 2, 3, a=5, b={}, c='7')

instead of

functools.partial(<function f at 0x100592d98>, 1, 2, 3, a=5, b={}, c='7')
msg123009 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2010-12-01 20:28
I would prefer the module.name without the repr decoration.
msg123010 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2010-12-01 20:33
I think the main purpose of repr is debugging, so I’d favor the unambiguous form (with the id) to the nice-looking one (module.name).
msg123011 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2010-12-01 20:36
Let me close this issue before any serious bikeshedding begins.  We can always reconsider when users complain that eval(repr(x)) does not work for their partial objects.
History
Date User Action Args
2010-12-01 20:36:42belopolskysetstatus: open -> closed

messages: + msg123011
2010-12-01 20:33:59eric.araujosetmessages: + msg123010
2010-12-01 20:28:38terry.reedysetstatus: pending -> open

messages: + msg123009
2010-12-01 20:07:22belopolskysetstatus: open -> pending
resolution: accepted
messages: + msg123006

stage: needs patch -> resolved
2010-11-19 21:20:18daniel.urbansetfiles: + issue4113b.diff

messages: + msg121569
2010-11-19 15:23:08belopolskysetassignee: belopolsky

messages: + msg121533
nosy: + lemburg
2010-11-19 14:47:49daniel.urbansetfiles: + issue4113.diff

nosy: + daniel.urban
messages: + msg121525

keywords: + patch
2010-11-18 09:54:57rhettingersetmessages: + msg121449
2010-11-18 02:12:52eric.araujosetnosy: + rhettinger, eric.araujo
messages: + msg121417
2010-06-11 00:01:30belopolskysetversions: + Python 3.2, - Python 3.1, Python 2.7
2010-06-11 00:01:22belopolskysetnosy: + belopolsky
title: functools.partial(), no __name__; wrong __doc__ -> Add custom __repr__ to functools.partial
messages: + msg107504

keywords: + easy, - patch
stage: needs patch
2008-10-20 02:23:29thomasleesetmessages: + msg74986
2008-10-19 20:38:25georg.brandlsetpriority: low
type: behavior -> enhancement
messages: + msg74982
nosy: + georg.brandl
versions: + Python 3.1, - Python 2.6, Python 3.0
2008-10-19 14:58:34thomasleesetfiles: + issue4113-01.patch
keywords: + patch
messages: + msg74977
nosy: + thomaslee
2008-10-17 22:45:23terry.reedysetnosy: + terry.reedy
messages: + msg74945
2008-10-17 22:45:00terry.reedysetcomponents: + Library (Lib), - Extension Modules
versions: + Python 3.0, Python 2.7
2008-10-13 11:45:14stribbcreate