Excellent contributions. I'm going to try to (partially) consolidate
what we've got.

REVIEW
=======
I'll start by reviewing the situation regarding default arguments.
There are two basic patterns for default arguments.

The first is
---
def fn(a=EXP):
    # body of function
---

The second is
---
def fn(a=None):
    if a is None:
        a = EXP
    # body of function
---

Here, EXP is any Python expression. A fairly gotcha is to use a list,
or some other mutable object, as EXP. This happens when you write
---
def fn(a=[]):
   # body of function
---
because then EXP = '[]' which will be evaluated just once, and every
call fn() will be using the same list! To avoid this you should use
the second pattern. I think there may be an example of this in the
standard Python tutorial.

(An aside. You probably need the second pattern if you EXP is, say,
([], []). Although technically immutable, this value has mutable
members. And can't be hashed, or use as a dictionary key or element of
a set.)

WHEN TO USE None
=================

If you want something mutable as the 'default argument' you have to
use the second pattern. If your default argument is immutable then you
can if you wish use the second pattern.

But you don't have to use the second pattern. When you use the second
pattern, the expression f(None) means 'create for me the default
argument' (and raise an exception if there isn't one).

Think about it. For immutable EXP, fn() is the same, whether fn is
coded using the first pattern or the second. But the value of fn(None)
depends very much on which pattern is used to code fn().

So here's the big conclusion (drum roll):
===
fn should be coded using the second pattern if we wish to pass None as
a sentinel argument to fn.
===

SUMMARY
=========
My suggestion was to use the second pattern to solve Peter O'Connor's
original problem. It can be done now, but is a bit verbose, and looses
useful information in help(fn).

Brice Parent's suggestion was to introduce a keyword deferred, like so
---
def fn(deferred a=EXP):
    # body of function
---
which I like to think of as a syntactic shorthand for the second pattern.

I sort of think we've now got a reasonable answer for Peter's problem.
What do you think, Peter? And Brice, are you happy with my
interpretation of your deferred keyword?

---
Jonathan
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to