I’m still not clear if this is a disagreement about something more than terminology, but as I understand it, other languages that have non-constant defaults use late binding, and call them “defaults”.
It seems to be a well accepted term. -CHB On Thu, Dec 9, 2021 at 12:45 AM Brendan Barnwell <brenb...@brenbarn.net> wrote: > On 2021-12-08 23:22, Chris Angelico wrote: > > On Thu, Dec 9, 2021 at 5:54 PM Brendan Barnwell <brenb...@brenbarn.net> > wrote: > >> > >> On 2021-12-08 20:36, Chris Angelico wrote: > >> > Remember, though: The comparison should be to a function that looks > like this: > >> > > >> > def f(a=[], b=_SENTINEL1, c=_SENTINEL2, d=_SENTINEL3): > >> > if b is _SENTINEL1: b = {} > >> > if c is _SENTINEL2: c = some_function(a, b) > >> > if d is _SENTINEL3: d = other_function(a, b, c) > >> > > >> > If you find the long-hand form more readable, use the long-hand form! > >> > It's not going away. But the introspectability is no better or worse > >> > for these two. The late-bound defaults "{}", "some_function(a, b)", > >> > and "other_function(a, b, c)" do not exist as objects here. Using PEP > >> > 671's syntax, they would at least exist as string constants, allowing > >> > you to visually see what would happen (and, for instance, see that in > >> > help() and inspect.signature). > >> > >> I don't want to get bogged down in terminology but I am becoming > >> increasingly frustrated by you using the term "default" both for things > >> that are values and things that are not, as if there is no difference > >> between them. > > > > That's absolutely correct: I am using the term "default" for anything > > that provides a default for an optional argument that was omitted. In > > some cases, they are default values. In other cases, they are default > > expressions. If your docstring says "omitting d will use the length of > > a", then the default for d is len(a). > > Your definition is somewhat circular, because you say that a > default is > "anything that provides a default". But that says "default" again. So > what is a default? > > By your definition, any arbitrary code inside a function body that > eventually assigns something to an argument name is a default. (It is > not clear to me whether you would consider some code a default if it may > or may not assign a value to an argument, depending on some conditions.) > So I don't agree with that definition. That can be default BEHAVIOR, > but it is function behavior; it is not an argument default. > > >> There are no late-bound defaults here, in the sense that > >> I mean, which as I said before has to do with default VALUES. There is > >> just code in the function body that does stuff. I am fine with code in > >> a function body doing stuff, but that is the purview of the function and > >> not the argument. An individual ARGUMENT having a default VALUE is not > >> the same as the FUNCTION defining BEHAVIOR to deal with a missing value > >> for an argument. > > > > In a technical sense, the default value for b is _SENTINEL1, but would > > you describe that in the docstring, or would you say that omitting b > > would use a new empty dictionary? You're getting bogged down, not in > > terminology, but in mechanics. At an abstract level, the default for > > that argument is whatever would be used if the argument is omitted. > > I don't agree. At an abstract level, there is no clear dividing > line > between what you call an argument default and just "arbitrary behavior > of the function". What if "what would be used" depends on random > numbers or data from some external source? > > Or, again, what you are describing is not an argument default (in > my > conception). It may be the BEHAVIOR of the function to do a certain > thing (like use a certain value in place of an omitted argument) but > unless that behavior is segmented and associated with the argument > itself (not merely part of the function's code flow) I don't consider it > an argument default. > > As for the docstring, yes, I might well mention _SENTINEL1 in the > docstring. I certainly wouldn't see anything wrong with that. That's > what the default is. Again, the function may USE that value in some > way, but that doesn't mean that's not what the default is; it just means > the function conditions its behavior on its argument value, as any > function may do on any argument value, omitted or not. I get the > impression you think that in a case like that the default "really is" > something else defined in the body of the function, but again I > disagree. The default really is _SENTINEL1. Conceptually we may > understand that the function will use that value in a special way, but > that is not really any different than understanding that passing "r" to > open() will open the file for reading while passing "w" will open it for > writing. It's just that to know how to use a function you need to know > more than the default values of the arguments; you need to know what > they MEAN, and (at least with current technology :-) we have no way of > deriving that from the source code. > > You're quite right that "at an abstract level" it may be the case > that > the default behavior is to do a certain thing, but I guess one way to > state my position would be that I think that is TOO abstract of a level > to worry about representing in code. At an abstract level I may say > "this function computes the number of paths of length N between the > given nodes in the given graph", but I don't expect that to be mentioned > in the signature or automatically provided in the docstring. I would > certainly WRITE it in the docstring, but I don't expect Python to deduce > that "abstract" level of meaning from code annotations and write that > docstring for me. > > In other words, I think mechanics is the right level to be at > here. We > cannot hope to capture the abstract level that you're describing, and I > think doing so will just muddle matters. At an abstract level we say > ""this function computes the number of paths of length N between the > given nodes in the given graph" but what we write is `def n_paths(graph, > node1, node2)`. I don't see any reason we need to be able to write > `len(x)` in the function signature just because at that abstract level > we think of it as something that may be computed later. This is > especially so because, as I mentioned above, there is no clear line > separating "code that we can write in a function to assign a default > value to an argument" and "code we can write in a function for other > purposes" --- and thus there is no way to distinguish behavior that is > "tied" to a particular argument from just code that uses any old > combination of values it wants. > > We write code in terms of instrumental units which necessarily are > at a > slightly more concrete level than the purely abstract or conceptual > realm of "what this function does". For instance, objects (which, until > now, every function argument, default or not, is). I don't see any > reason why late-bound defaults should be represented in code in a way > that attempts to capture this abstract level when other aspects of > functions are not and cannot be. > > > To justify this, please explain WHY it is so important for defaults to > > all be objects. Not just "that's how they are now", but why that is an > > important feature. > > Because I'm used to reasoning about Python code in terms of > operations > on objects, and so are a lot of other people. Everything I or anyone > else currently needs to know about how functions and their arguments > work in Python can be thought of in terms of objects. Why add a new > complication? I mean, okay, maybe that is really just saying "that's > how they are now", although it's more like "right now defaults are part > of the big set of things that are objects and this change would peel > them off and create a new type of thing". > > But apart from that, I think part of what makes Python a nice > language > is the way that many language functions are represented in terms of > objects, for instance the iterator and descriptor protocols. The idea > of the object as a locus of functionality --- that the way you "do > something" (like loop or access an attribute) is represented as "get an > object representing the functionality and call certain methods on it" > --- gives unity to many Python features. It's true that's a pretty > abstract reason, but I think it's a legit one. > > Also, let's remember that burden of evidence is really the other > way > around here. Can you really explain WHY it is so important for > late-bound defaults to be represented with special syntax of the type > you propose? Not only can you not rely on "that's how they are now" > (because they're not), but in fact you must overcome the reverse > argument, namely that people have been doing pretty well with just > early-bound defaults for decades now. In other words, even if it is not > particularly important for defaults to be objects, it may still be more > important than being able to write a "late-bound default" (aka "behavior > in the function body") in the signature. > > -- > Brendan Barnwell > "Do not follow where the path may lead. Go, instead, where there is no > path, and leave a trail." > --author unknown > _______________________________________________ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-le...@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at > https://mail.python.org/archives/list/python-ideas@python.org/message/EXDGAZCHULMFAIP4ARLILRQF76GIILWF/ > Code of Conduct: http://python.org/psf/codeofconduct/ > -- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/P22UIWHOYOJC7QESKLYNX5LF4RIL6Q3T/ Code of Conduct: http://python.org/psf/codeofconduct/