Greg Ewing writes:
To my mind, the signature consists of information that a static type checker would need to verify that a call is valid. That does not include default values of arguments.
That's a parsimonious and reasonable definition, and the one historically used by Emacs Lisp. But the definition that says that, *in addition*, it includes the default values is also reasonable. Note that in your definition, the signature *does*, however, include the fact that defaulting (omitting) those arguments is allowed, otherwise abbreviated calls would be flagged by the static type checker. Once you've allowed defaults, I think the obvious syntactic place to put them is in the def statement, because they are useful as documentation.
Where do we draw the line? How much of the behaviour of the function do we want to move into the header?
To my mind that's a programming style question. Python has made the decision that anything that evokes a specific object (including a function or a code object) can go there.[1] For me in practice that's a good dividing line. Except that I would never put a function or code object there only to immediately evaluate it: # Just too ugly for me! def foo(x=lambda: random.randint(0,9)): x = x() # ... Footnotes: [1] I don't think this was the main intended effect of early binding of defaults, but it is an effect.