1

Suppose I have a function foo(x,k) and suppose x is a list. I want k to default to the length of the list. Do I just write:

def foo(x, k=1):
  k = len(x)
  ..
end

I just want to run foo with one argument, namely, x.

lord12
  • 2,837
  • 9
  • 35
  • 47
  • 2
    Out of curiosity, why do you need a second parameter to your function then, rather than just using `k` as internally declared variable, defaulting to `len(x)`? – favoretti Feb 26 '13 at 03:57
  • Why even have k then? – the wolf Feb 26 '13 at 03:58
  • The function I am defining is recursive and relies on k as an index. – lord12 Feb 26 '13 at 03:58
  • 1
    @lord12: If `k` is always going to be the length of the list, why do you have it as an argument? – Blender Feb 26 '13 at 03:59
  • The last sentence is quite confusing. I think you mean that you want to be _able_ to call `foo` with one argument. But your last sentence says that you only ever want to call `foo` with one argument, which would make `k` a pointless parameter. Could you edit your question for clarity? – senderle Feb 26 '13 at 04:12

3 Answers3

9

You should do:

def foo(x, k=None):
    if k is None:
        k = len(x)
    ...

Note that this could be made more compact as:

def foo(x, k=None):
    k = k or len(x)
David Robinson
  • 77,383
  • 16
  • 167
  • 187
  • This construct -- while it works -- is usually used if k is a mutable -- like a list. Why not use keyword arguments? – the wolf Feb 26 '13 at 04:16
  • 2
    @thewolf, I disagree. This is the most idiomatic approach to specifying a dynamically defined default. Mutability has nothing to do with it. – senderle Feb 26 '13 at 04:19
  • @senderle: Are you saying that optional keyword arguments are NOT idiomatic? That this construct is more idiomatic? Really?? – the wolf Feb 26 '13 at 04:20
  • @thewolf, huh? This _is_ an optional keyword argument. – senderle Feb 26 '13 at 04:21
  • 1
    @senderle: I am referring to [this](http://effbot.org/zone/default-values.htm) and [this](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument/1133013#1133013) and [this](http://docs.python.org/2/tutorial/controlflow.html#keyword-arguments) as examples. The assignment of `k=None` then testing for None has always struck *me* as a construct for use with optional mutables mostly and use `k=kwargs.get('k',len(l))` for others since in that one line you are testing and assigning. I didn't say it was *wrong* at all; just surprised – the wolf Feb 26 '13 at 04:31
  • 1
    Using `**kwargs` instead of a specific default keyword argument has a few disadvantages in this case. First, it's almost 25% slower according to a test I just did. (`get` is pretty slow.) Second, and more importantly, it disallows passing in `k` as a positional argument. Third, and most importantly, it accepts and silently ignores _any_ keyword argument except `k`, whereas the above throws an error if passed an unexpected keyword argument. – senderle Feb 26 '13 at 04:38
  • 1
    @senderle: agreed, and I would add a fourth- it makes `help(foo)` less transparent. – David Robinson Feb 26 '13 at 04:44
  • 2
    @senderle: I am convinced. I tested the speed and indeed `get` is slower and your other arguments are correct. +1 for this and I have edited my post. I am here to learn... – the wolf Feb 26 '13 at 06:01
  • 1
    @senderly: Just to clarify: `def foo(x, k=None)` is **not** an optional keyword argument. It is a positional argument with a default value. Run `>>> inspect.getargspec(foo)` -- returns `ArgSpec(args=['x', 'k'], varargs=None, keywords=None, defaults=(None,))` If you have `>>> def foo(x, **k): pass` then getarspec returns `ArgSpec(args=['x'], varargs=None, keywords='k', defaults=None)` It is a positional arg with a default value... – dawg Feb 26 '13 at 22:09
  • @drewk, well, sort of. If we're talking about the function _definition_, then technically it's a _parameter_ with a default value. And normal parameters in Python accept both [keyword arguments](http://docs.python.org/2/tutorial/controlflow.html#keyword-arguments) and positional arguments. Therefore `foo` accepts `k` as an optional keyword argument. I could have worded my comment better, but that's what I meant. – senderle Feb 27 '13 at 01:34
2

Just do:

def foo(x):
    k = len(x)

You don't have to pass in k to this function. You can just use a local variable k.

In case you have to use k then you can just do:

def foo(x,k):
    k = len(x)

Although this doesn't serve any purpose.

fatrock92
  • 827
  • 1
  • 8
  • 16
  • I think you've misunderstood the question. Admittedly, it's not very clear. I think the point is that `k` should be an optional parameter. It should only take the value of `len(x)` if `k` is not supplied. – senderle Feb 26 '13 at 04:09
0

If your intent is to have an optional k in no particular order with k=len(l) the default, you can use an optional keyword argument like so:

def f(l,**kwargs):
    k=kwargs.get('k',len(l))    
    # if k is in kwargs, it overrides the default of len(l)..
    print 'l={}, len(l)={}, k={}'.format(l,len(l),k)

f([1,2,3])  
f([1,2,3],k=1)  

Prints:

l=[1, 2, 3], len(l)=3, k=3
l=[1, 2, 3], len(l)=3, k=1

As pointed out in the comments, this is a trade-off with other considerations of speed and parameter position in David Robinson's approach.

Community
  • 1
  • 1
the wolf
  • 34,510
  • 13
  • 53
  • 71