|
msg75928 - (view) |
Author: scott sadler (ssadler) |
Date: 2008-11-16 06:32 |
Calling a function created by _functools.partial as a method raises an
exception:
"TypeError: method_new() takes exactly n non-keyword arguments (0 given)"
Where method_new is the function passed into partial() and n is the
number of arguments it expects.
This does not happen when using a python version of partial().
Strangely, in the circumstance that I originally encountered the bug,
there was one instance that I was doing this and it _DID WORK_. The
function being passed into partial() was the same as in the place where
it was failing. The only significant difference that I could see was
that the input function to partial() was being imported, rather than
being defined in the same namespace as it was used I was unable to
reproduce it in my test case (attatched).
Tested on 2.6 and 2.5.2
|
|
msg75942 - (view) |
Author: scott sadler (ssadler) |
Date: 2008-11-16 20:24 |
A short update, I believe that the reason that it was working in one
instance was because of some abstractions by a base class (Django model,
get_absolute_url).
|
|
msg75945 - (view) |
Author: Calvin Spealman (ironfroggy) |
Date: 2008-11-16 22:44 |
I don't think this is any kind of bug, it is simply a product of only
function objects being decorated automatically as methods. Your python
version works because it is, in fact, a function. _functools.partial
objects are not functions, but simply callable objects.
|
|
msg75946 - (view) |
Author: Raymond Hettinger (rhettinger) *  |
Date: 2008-11-16 23:03 |
Reclassifying as a feature request.
A descriptor could be added to partial()
so that it too would have automatic
method binding just like pure python functions.
|
|
msg97470 - (view) |
Author: Christophe Simonis (Christophe Simonis) |
Date: 2010-01-09 20:59 |
I followed the advice of Raymond and implement a descriptor on partial.
|
|
msg98490 - (view) |
Author: Alexander Belopolsky (Alexander.Belopolsky) |
Date: 2010-01-29 00:25 |
Christophe,
It looks like your patch goes out of its way to avoid creating nested partials. This is a worthwhile goal and I think it should be done in partial_new so that partial(partial(f, x), y) returns partial(f, x, y).
If fact, I was surprised to learn that current partial implementation does not behave this way:
>>> partial(partial(f, 1), 2).func
<functools.partial object at 0x100435af8>
Does anyone know the reason for the current behavior? It is possible that I am missing some subtlety related to keyword arguments.
|
|
msg98675 - (view) |
Author: Alexander Belopolsky (Alexander.Belopolsky) |
Date: 2010-02-01 19:09 |
Please see issue7830 for a related patch.
|
|
msg99776 - (view) |
Author: Jack Diederich (jackdied) *  |
Date: 2010-02-22 16:33 |
I'm having some trouble wrapping my head around this one. It isn't obvious to me that
my_method(*args):
print(args)
class A():
meth = partial(my_method, 'argA')
ob = A()
ob.meth('argB')
should print (<A object at 0x1234>, 'argA', 'argB') and not
('argA', <A object at 0x1234>, 'argB')
The patch seems to prefer the first form but if you are using a partial shouldn't you expect 'argA' to always be the first argument to the partial-ized function?
|
|
msg99813 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2010-02-22 19:11 |
I would expect the second and would view the first as a bug.
|
|
msg99956 - (view) |
Author: Jack Diederich (jackdied) *  |
Date: 2010-02-23 21:35 |
We talked about it at sprints and the semantics are ambiguous and there are alternatives.
Ambiguous:
def show_funcs(*args): print(args)
class A():
run = partial(1)
ob = A()
ob.run(2,3)
Should this print (self, 1, 2, 3) or (1, self, 2, 3)? And what about
partial(ob.run, 2)(3)
Alternatives: partial is a convenience function not an optimization (it doesn't offer a speedup. So you can write a lambda or named function that has the exact semantics you want without suffering a speed penalty.
So unless there are a lot of good use cases with obvious behavior, we should refuse the temptation to guess and leave partial as-is.
|
|
msg99957 - (view) |
Author: Jack Diederich (jackdied) *  |
Date: 2010-02-23 21:37 |
correction:
run = partial(1)
should have been
run = partial(show_funcs, 1)
|
|
msg156712 - (view) |
Author: Matt Joiner (anacrolix) |
Date: 2012-03-24 18:23 |
I've attached a patch that implements the descriptor protocol for functools.partial with minimum changes.
|
|
msg181582 - (view) |
Author: Ulrich Eckhardt (eckhardt) |
Date: 2013-02-07 08:36 |
Just for the record, the behaviour is documented, unfortunately in the very last line of the functools documentation: "Also, partial objects defined in classes behave like static methods and do not transform into bound methods during instance attribute look-up."
Concerning how exactly they should behave during that lookup, I'd use the least surprising variant, namely that they are not treated differently from other functions: The first parameter is implicitly "self".
|
|
msg181658 - (view) |
Author: Matt Joiner (anacrolix) |
Date: 2013-02-08 04:02 |
What's preventing this from being committed and closed?
|
|
msg182943 - (view) |
Author: Ulrich Eckhardt (eckhardt) |
Date: 2013-02-25 14:19 |
There is at least one thing that is missing in the patch, it lacks the necessary tests. The partialbug.py demonstrates the issue, it could be used as a base. However, even then, there is still one thing that is problematic: The fact that partial() returns something that behaves like a static method is documented and changing that is not backward compatible.
I still think that something like this should become part of Python though. Jack Diederich argues that you can use lambda to achieve the same, but that is not always true. If you want to bind an argument to the current value of a variable instead of a constant, lambda fails. You need the closure created by a function call to bind those variables inside a local function. Having a dedicated function for that is IMHO preferable to people copying the Python-only equivalent of partial() to achieve the same effect or even inventing their own.
|
|
msg182946 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2013-02-25 15:02 |
See also issue 11470.
|
|
| Date |
User |
Action |
Args |
| 2013-02-25 15:02:11 | r.david.murray | set | messages:
+ msg182946 |
| 2013-02-25 14:19:14 | eckhardt | set | messages:
+ msg182943 |
| 2013-02-08 09:20:10 | Ramchandra Apte | set | versions:
+ Python 3.3, Python 3.4, - Python 3.0 |
| 2013-02-08 04:02:49 | anacrolix | set | messages:
+ msg181658 |
| 2013-02-07 08:36:05 | eckhardt | set | nosy:
+ eckhardt messages:
+ msg181582
|
| 2012-03-24 18:23:40 | anacrolix | set | files:
+ functools.partial-descrget.patch
messages:
+ msg156712 |
| 2012-03-24 16:14:44 | anacrolix | set | nosy:
+ anacrolix
|
| 2011-12-11 01:28:07 | jcea | set | nosy:
+ jcea
|
| 2010-02-23 21:37:15 | jackdied | set | messages:
+ msg99957 |
| 2010-02-23 21:35:44 | jackdied | set | messages:
+ msg99956 |
| 2010-02-22 19:11:42 | r.david.murray | set | nosy:
+ r.david.murray messages:
+ msg99813
|
| 2010-02-22 16:33:51 | jackdied | set | messages:
+ msg99776 |
| 2010-02-18 21:09:22 | jackdied | set | nosy:
+ jackdied
|
| 2010-02-01 19:09:23 | Alexander.Belopolsky | set | messages:
+ msg98675 |
| 2010-01-29 00:25:25 | Alexander.Belopolsky | set | nosy:
+ Alexander.Belopolsky messages:
+ msg98490
|
| 2010-01-09 20:59:31 | Christophe Simonis | set | files:
+ issue4331.patch keywords:
+ patch messages:
+ msg97470
|
| 2009-03-05 20:23:48 | Christophe Simonis | set | nosy:
+ Christophe Simonis |
| 2008-12-03 05:03:56 | belopolsky | set | nosy:
+ belopolsky |
| 2008-11-16 23:03:10 | rhettinger | set | type: behavior -> enhancement messages:
+ msg75946 nosy:
+ rhettinger versions:
+ Python 3.0, Python 2.7, - Python 2.6, Python 2.5 |
| 2008-11-16 22:44:28 | ironfroggy | set | nosy:
+ ironfroggy messages:
+ msg75945 |
| 2008-11-16 20:24:31 | ssadler | set | messages:
+ msg75942 |
| 2008-11-16 06:32:58 | ssadler | create | |