Keyword arguments - strange behaviour?

F

Fuzzyman

Steven said:
complex,

Interesting. I would have thought that my example was pretty simple.
Maybe it would be helpful to generalize it to:

def foo(bar, baz, spam=badger(x, y, z)):
...

All it does is use a default value that was produced by a function call.
I'm surprised you haven't run into this situation before...

Of course, what is complex or simple is a matter of personal opinion. I
use this pattern so often that it's quite simple to me, but I guess I
can understand that if you don't use such a pattern, it might seem
foreign to you.

Steve


Hello Steve,

It wasn't that part of the example that I thought was over complex.
(although it's not a 'pattern' I use often). You suggested that if we
had dynamic evaluation of default values, you would have to replace it
with :
Now that I thought was over complex... when all you wanted to do was
put a constant into your default value !

Having said that I see Steve's point about not knowing the namespace
when the function will be called.
Regards,

Fuzzy
http://www.voidspace.org.uk/python/index.shtml
 
A

Alex Martelli

I'm really looking for a neat way to do the following:

def method(a,b,opt1=None,opt2=None,opt3="",opt4=None):
if opt1 is None: opt1=[]
if opt2 is None: opt2={}
if opt4 is None: opt4=[]

Python syntax is normally so neat but this just looks a mess if there
are lots of parameters.

There's a decorator for that in the Cookbook (sorry, don't recall the
recipe number, but, it's on the site, and it got into the 2nd edition
which we're still expecting to have on paper at PyCon) -- basically
wrapping a function with a wrapper that does a copy.deepcopy on the
defaults values at each call (efficiency of course goes down the drain,
but you _did_ say "apart from efficiency"!-).


Alex
 
A

Alex Martelli

the default params are evaluated at the definition. However, I still
can't give a nice looking solution on how to re-write a function to
have empty mutable values as default arguments: eg.

def method(a,b,opt1=[],opt2=None,opt3="",opt4={})

How could I re-write this (especially if there are perhaps 20 optional
parameters,any number of which may have mutable defaults) without
writing 20 "if opt1 is None: opt1=[]" statements?

I don't have the recipe I mentioned at hand, but what about:

def makebrianhappy(f):
saved_defaults = f.func_defaults
def with_fresh_defaults(*a, **k):
f.func_defaults = copy.deepcopy(saved_defaults)
return f(*a, **k)
with_fresh_defaults.__name__ = f.__name__
return with_fresh_defaults

@ makebrianhappy
def method(a, b, opt1=[], opt2=None, opt3="", opt4={}):
...

I've added spaces after commas to make ME happy too (lack of such spaces
is my least favourite Python irritation;-), but I guess the semantics of
this (UNTESTED) code would work even without that;-).


Alex
 
S

Steven Bethard

Fuzzyman said:
It wasn't that part of the example that I thought was over complex.
(although it's not a 'pattern' I use often). You suggested that if we
had dynamic evaluation of default values, you would have to replace it
with :



Now that I thought was over complex... when all you wanted to do was
put a constant into your default value !

Ahh. Yeah, the thing above is a bit complex, but it keeps the same
namespaces -- matcher is only available to foo, not the enclosing
class/module. Point taken of course. ;)

Steve
 
F

Fuzzyman

Steven said:
Ahh. Yeah, the thing above is a bit complex, but it keeps the same
namespaces -- matcher is only available to foo, not the enclosing
class/module. Point taken of course. ;)

Steve

I see. I may be wrong on this... *but* I thought the only time when a
variable defined in the same scope as a function wouldn't be available
in the same namespace is when the function is a global but the variable
isn't ? In which case you deserve a NameError if you try and use the
variable as a default value.......

Are there any other circumstances when they wouldn't be in the same
namespace ?
Regards,

Fuzzyman
http://www.voidspace.org.uk/python/index.shtml
 
S

Steven Bethard

Fuzzyman said:
I see. I may be wrong on this... *but* I thought the only time when a
variable defined in the same scope as a function wouldn't be available
in the same namespace is when the function is a global but the variable
isn't ?

Sorta depends on what you mean by "available in the same namespace":

py> class C(object):
.... def f(matcher=re.compile(r'...')):
.... pass
....
py> class D(object):
.... matcher = re.compile(r'...')
.... def f():
.... pass
....
py> class E(object):
.... class f(object):
.... matcher = re.compile(r'...')
.... def __new__(cls):
.... pass
....
py> c = C()
py> c.matcher
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: 'C' object has no attribute 'matcher'
py> d = D()
py> d.matcher
<_sre.SRE_Pattern object at 0x01142F20>
py> e = E()
py> e.matcher
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: 'E' object has no attribute 'matcher'

Now in all three classes, the callable 'f' can access matcher -- it's
either in f's namespace or within an enclosing namespace.

However, moving the 'matcher' declaration up one level (as in class D)
adds matcher to the enclosing class's namespace. The current code
(class C) and my proposed code (class E) do not add 'matcher' to the
enclosing class's namespace -- they keep it within f's namespace.

This is what I considered to be 'polluting the namespace' -- adding
extra things that aren't used by other parts of the class to the class's
namespace. (Of course, this only holds if, as in my code, matcher is
only needed within f.)

Does that make my problem clearer?

Steve
 

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

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top