Function __defaults__

S

Steven D'Aprano

Consider this in Python 3.1:

.... return a
....23


Is this an accident of implementation, or can I trust that changing
function defaults in this fashion is guaranteed to work?
 
T

Terry Reedy

Consider this in Python 3.1:


... return a
...
23


Is this an accident of implementation, or can I trust that changing
function defaults in this fashion is guaranteed to work?

Interesting question. It seems not to be documented, so I would not
count on anything. This is a bit of a gray area, and if you get no
answer here, try pydev list, perhaps as a request that special names be
more completely documented, even is just as implementation details
subject to change.
 
B

Benjamin Kaplan

Consider this in Python 3.1:


...     return a
...
23


Is this an accident of implementation, or can I trust that changing
function defaults in this fashion is guaranteed to work?

Jython 2.5.1 (Release_2_5_1:6813, Sep 26 2009, 13:47:54)
[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_24
Type "help", "copyright", "credits" or "license" for more information..... return a
....42

I'm going to go with implementation detail.
 
K

Ken Seehart

Consider this in Python 3.1:


... return a
...
23


Is this an accident of implementation, or can I trust that changing
function defaults in this fashion is guaranteed to work?

This is documented in python 3, so I would expect it to be stable (until
python 4, that is)
http://docs.python.org/py3k/whatsnew/3.0.html#operators-and-special-methods
http://docs.python.org/py3k/library/inspect.html#types-and-members

The f.__defaults__ attribute was previously known as f.func_defaults (in
python 2.x), which has been around, documented and stable for quite a while.

So it's probably just as safe as any other monkey patching technique. :)

Best of luck,
Ken
 
D

Daniel Kluev

http://docs.python.org/dev/reference/datamodel.html
Callable types
....
Special attributes:
....
__defaults__ A tuple containing default argument values for those
arguments that have defaults, or None if no arguments have a default
value Writable

I don't see any 'implementation detail' mark there, and 'Writable'
IMHO means it can be used.

Jython 2.5.1 (Release_2_5_1:6813, Sep 26 2009, 13:47:54)

In 2.x it was func_defaults (http://docs.python.org/reference/datamodel.html)
__defaults__ is 3.x feature
 
K

Ken Seehart

Oops, I must correct myself. Please ignore my previous post.

As Daniel points out, Writable is specified in the Python 3
documentation. Apparently I was reading the documentation with only my
right eye open, and the Writable tag fell on my blind spot.
I concur that this unambiguously implies that the attribute should work
as advertised after being written.

This is not a bug in Jython. As Daniel points out the attribute was
renamed from func_defaults to __defaults__ in python 3.

Jython 2.5.2 (Release_2_5_2:7206, Mar 2 2011, 23:12:06)
[Java HotSpot(TM) Client VM (Sun Microsystems Inc.)] on java1.6.0_24
Type "help", "copyright", "credits" or "license" for more information..... print x
....
So it works correctly in Jython 2.x.

Conclusion: Not an implementation detail, and safe to use.

Ken
 
D

Daniel Kluev

Good point, Benjamin.  I didn't think of testing on Jython before
answering.  For practical purposes it's a really good idea to test obscure
features against all potential target platforms.

In this case, I would argue that Benjamin's test demonstrates a bug in
Jython.

It doesn't. __defaults__ was added in 3.x (and it is documented).
Prior to that, in 2.x, there was func_defaults.

Jython is not in 3.x yet, so you should not expect 3.x features there.
As for func_defaults, its there and supported as documented:

Jython 2.5.1+ (Release_2_5_1:exported, Mar 21 2010, 01:00:17)
[Java HotSpot(TM) Server VM (Sun Microsystems Inc.)] on java1.6.0_22
Type "help", "copyright", "credits" or "license" for more information..... return a
....456
 
T

Terry Reedy

Good point, Benjamin. I didn't think of testing on Jython before
answering. For practical purposes it's a really good idea to test
obscure features against all potential target platforms.

In this case, I would argue that**Benjamin's test demonstrates a bug in
Jython.

Benjamin's 'test' only tested that he could add a new attribute to a
function object, as he did not use the proper 2.x name, func_defaults.
One could counter by pointing out that the documentation does not
specify that the __defaults__ attribute is writable.

The 3.x docs, as another pointed out, does so specify. The same was true
in 2.x at least by 2.5

http://docs.python.org/release/2.5.4/ref/types.html
"func_defaults A tuple containing default argument values for those
arguments that have defaults, or None if no arguments have a default
value Writable"

So if the following does not work in Jython 2.5

def f(a=42) :
return a
f()
# 42
f.func_defaults = (23,)
f()
# 23

then it *does* have a bug with respect to matching the Python 2.5 spec.
 
K

Ken Seehart

Gotta love that email latency. :-D
Ken

Good point, Benjamin. I didn't think of testing on Jython before
answering. For practical purposes it's a really good idea to test obscure
features against all potential target platforms.

In this case, I would argue that Benjamin's test demonstrates a bug in
Jython.
It doesn't. __defaults__ was added in 3.x (and it is documented).
Prior to that, in 2.x, there was func_defaults.

Jython is not in 3.x yet, so you should not expect 3.x features there.
As for func_defaults, its there and supported as documented:

Jython 2.5.1+ (Release_2_5_1:exported, Mar 21 2010, 01:00:17)
[Java HotSpot(TM) Server VM (Sun Microsystems Inc.)] on java1.6.0_22
Type "help", "copyright", "credits" or "license" for more information.... return a
...456
 
S

Steven D'Aprano

On 4/24/2011 2:58 AM, Steven D'Aprano wrote: [...]
Is this an accident of implementation, or can I trust that changing
function defaults in this fashion is guaranteed to work?

This is documented in python 3, so I would expect it to be stable (until
python 4, that is)
http://docs.python.org/py3k/whatsnew/3.0.html#operators-and-special-
methods


Thanks to everyone who replied. Obviously my google-foo was weak
yesterday, because I did search for an answer.

However, __getitem__ appears to be ignored when looking up defaults:

.... def __getitem__(self, i):
.... print("magic!")
.... return super().__getitem__(i)
........ return a+b
....
f.__defaults__ = Magic(f.__defaults__)
f.__defaults__[0]
magic!
2
42


Which is a pity, because I had an awesome idea for a hack to "fix" the
mutable default function argument gotcha with a decorator, but
unfortunately it relies on __getitem__ being called.

def fixed_default(func):
class Magic(tuple):
def __getitem__(self, i):
x = super().__getitem__(i)
if x == []:
return list()
return x
func.__defaults__ = Magic(func.__defaults__)
return func
 
C

Colin J. Williams

This is documented in python 3, so I would expect it to be stable (until
python 4, that is)
http://docs.python.org/py3k/whatsnew/3.0.html#operators-and-special-methods
http://docs.python.org/py3k/library/inspect.html#types-and-members

The f.__defaults__ attribute was previously known as f.func_defaults (in
python 2.x), which has been around, documented and stable for quite a
while.

So it's probably just as safe as any other monkey patching technique. :)

Best of luck,
Ken

Wouldn't it make more sense to return a dictionary instead of a tuple?

Colin W.
 
K

Ken Seehart

Wouldn't it make more sense to return a dictionary instead of a tuple?

Colin W.

I assume you mean making the value of f.__defaults__ a dictionary
instead of a tuple.

A dictionary would be slower to process since it would have to iterate
the dictionary keys and assign arguments by name.
Since argument defaults can only be applied to the rightmost contiguous
sequence of zero or more parameters (excluding *args,**kwargs), a tuple
is sufficient to cover all cases, so a dictionary would provide no
advantage.
Also, a dictionary would produce an unnecessary error case (if a key in
the dictionary is not the name of an argument).

Good question though.

Cheers,
Ken
 
C

Colin J. Williams

I assume you mean making the value of f.__defaults__ a dictionary
instead of a tuple.

A dictionary would be slower to process since it would have to iterate
the dictionary keys and assign arguments by name.
Since argument defaults can only be applied to the rightmost contiguous
sequence of zero or more parameters (excluding *args,**kwargs), a tuple
is sufficient to cover all cases, so a dictionary would provide no
advantage.
Also, a dictionary would produce an unnecessary error case (if a key in
the dictionary is not the name of an argument).

Good question though.

Cheers,
Ken
I doubt that this functionality would be used in time critical work and
so I suggest that efficiency is not a key consideration.

Loss of information is perhaps more important. With the tuple being
returned, the user is not informed that the value is associated with the
name "a"

Colin W.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Staff online

Members online

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,432
Latest member
GTRNorbert

Latest Threads

Top