Alex Hall writes:
In all cases it's not immediately clear what the actual default value is, or even what kind of object is meant to be passed to that parameter.
I agree with the basic principle, but I'm not sure this is a very strong argument. First, if you want to indicate what the type of the actual argument should be, we have annotations for that exact purpose. (Granted, these don't deal with situations like "should be nonempty," see below.) Second, in many cases the default value corresponding to None is the obvious mutable falsey: an empty dict or list or whatever. Viz:
``` ChainMap.new_child(m={}) StreamHandler(stream=sys.stderr) json.dump(..., cls=JSONEncoder, ...) ```
In the case of json.dump, I don't know why that isn't already the signature, does anyone know?
Assuming that in many other cases we could fix the signature in this way, are the leftovers like StreamHandler important enough to justify a syntax change? I have no opinion on that, it's a real question.
The point is that the signature now conveys the default as well as the type of the parameter,
Except that it doesn't convey the type in a Pythonic way. How much of the API of dict must 'm' provide to be acceptable to ChainMap? Are there any optional APIs (i.e., APIs that dict doesn't have but ChainMap would use if available) that must have correct semantics or ChainMap goes "BOOM!"? Are non-empty mappings acceptable?! This doesn't change my lack of opinion. :-) Clearly, it's useful to know that dicts (probably including non-empty ones ;-) are acceptable to new_child, that sys.std* output streams are (probably ;-) acceptable to StreamHandler, and that cls should (probably ;-) encode Python data to JSON. Those are all good enough bets that I would take them. But it isn't as big a help as it looks on first sight, in particular to somebody who has a partially duck-type-compatible object they would like to use.