> The trouble with explicitly overriding keywords is that it still requires old code to > be changed whenever a new keyword is added...
Nope. That's the exact thing my proposal avoids. I'm not sure it also does everything everyone else wants it to do, so it may be a bad idea, but you would not have to change old code, ever. For the purpose of this discussion, let's say that if any code implicitly enables a new feature (by simply using it), all the code in that file is 'new code' in the context of the specific feature (a bit like how `yield` works). If `until` was a new keyword, any file that used it as a keyword would be new code. Any other files are 'old code'. New code could still import an object named `until` from old code. It just could not import it as `until`. So `import until as upto` is fine, but `import until` is a NameError *in new code*. In old code, `until` is still just a name. We would also allow `name.until` and `dance(until="am")` in new code, so that we can still reference names in old code (without them becoming names in new code). If `self.until = something` appeared anywhere in new code, or any local assignment to `until` (including class and def statements) appeared inside a subclass definition within new code, that would need to be checked for a runtime NameError (not very often, but sometimes). In practice, many libraries would alias names that became keywords, so new code could use the new name without restrictions, but old code would carry on working with the old name. TLDR: The syntax and semantics of old code would remain totally unchanged. -- Carl Smith carl.in...@gmail.com On 17 May 2018 at 01:21, Steven D'Aprano <st...@pearwood.info> wrote: > On Thu, May 17, 2018 at 10:58:34AM +1200, Greg Ewing wrote: > > > The trouble with explicitly overriding keywords is that it > > still requires old code to be changed whenever a new keyword > > is added, which as far as I can see almost competely defeats > > the purpose. If e.g. you need to change all uses of given > > to \given in order for your code to keep working in > > Python 3.x for some x, you might just as well change it > > to given_ or some other already-legal name. > > Well, maybe. Certainly using name_ is a possible solution, and it is one > which has worked for over a quarter century. > > We can argue about whether \name or name_ looks nicer, but \name > has one advantage: the key used in the namespace is actually "name". > That's important: see below. > > > > The only remotely legitimate use I can think of is for > > calling APIs that come from a different language, but the > > same thing applies there -- names in the Python binding can > > always be modified somehow to make them legal. > > Of course they can be modified. But having to do so is a pain. > > With the status quo, when dealing with external data which may include > names which are keywords, we have to: > > - add an underscore when we read keywords from external data > - add an underscore when used as obj.kw literals > - add an underscore when used as getattr("kw") literals > - conditionally remove trailing underscore when writing to external APIs > > to: > > - do nothing special when we read keywords from external data > - add a backslash when used as obj.kw literals > - do nothing special when used as getattr("kw") literals > - do nothing special when writing to external APIs > > > I think that overall this pushes it from a mere matter of visual > preference \kw versus kw_ to a significant win for verbatim names. > > Let's say you're reading from a CSV file, creating an object from each > row, and processing it: > > # untested > reader = csv.reader(infile) > header = next(reader) > header = [name + "_" if name in keywords.kwlist() else name for name in > header] > for row in reader: > obj = SimpleNamespace(*zip(header, row)) > process(obj) > > > The consumer of these objects, process(), has to reverse the > transformation: > > def process(obj): > for name, value in vars(obj): > if name.endswith("_") and name[:-1] in keywords.kwlist(): > name = name[:-1] > write_to_external_API(name, value) > > > Verbatim names lets us skip both of these boilerplate steps. > > An interesting case is when you are using the keywords as hard-coded > names for attribute access. In the status quo, we write: > > obj.name_ > obj.getattr("name_") > > In the first line, if you neglect the _ the compiler will complain and > you get a syntax error. In the second line, if you neglect the _ you'll > get no warning, only a runtime failure. > > With verbatim names, we can write: > > obj.\name > obj.getattr("name") # Don't escape it here! > > In this case, the failure modes are similar: > > - if you forget the backslash in the first line, you get a > SyntaxError at compile time, so there's no change here. > > - if you wrongly include the backslash in the second line, > there are two cases: > > * if the next character matches a string escape, say \n > or \t, you'll get no error but a runtime failure; > > (but linters could warn about that) > > * if it doesn't match, say \k, you'll now get a warning > and eventually a failure as we depreciate silently > ignoring backslashes. > > > -- > Steve > _______________________________________________ > Python-ideas mailing list > Python-ideas@python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ >
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/