Here’s a concrete proposal.

tl;dr: `nameof x == "x"`, and `nameof x.y == "y"`.

Rationale:

Even though as far as Python is concerned `nameof x.y` is identical to `"y"`, 
it can make a difference to human readers—and to at least two classes of 
automated tools.

When refactoring code to rename something, there is no way to tell whether a 
string—or a substring in a larger string—that matches the name should be 
changed. But a nameof expression is unambiguously a reference to the name, and 
therefore the tool knows that it needs to change.

For example:

    class Spam:
        cheese = 10
        def __repr__(self)
            return f"<{type(self).__name__} at {id(self)} {nameof self.cheese}: 
{self.cheese}>"

If I ask my IDE to rename cheese to beans, that `nameof self.cheese` is 
unambiguous: it clearly should be changed to `nameof self.beans`. If I had just 
included the substring “cheese” within the string, it would need some kind of 
heuristics or trained AI or something to figure that out.

Similarly for this example:

    rpc.register(nameof spam, spam)

Again, if I just used the string "spam", renaming the function spam to eggs 
would be ambiguous.

And if I used spam.__name__, this would be unambiguous, but potentially 
incorrect. For example:

    spam = SpamHandler.handle
    rpc.register(spam.__name__, spam) # oops




 (spam could be the name of a lambda, or a function defined as bar and copied 
to spam, or a bound classmethod SpamHandler.spam

This is different from registering "spam” because if I rename the function the 
refactoring tool will automatically change the string. And it’s different from 
registering spam.__name__ because it works even if spam is a name for a lambda, 
or another name for a function defined as eggs.

Grammar:

    atom ::= identifier | literal | enclosure | nameof_atom
    nameof_atom ::= "nameof" nameof_name
    nameof_name ::= identifier | attributeref

Semantics:

The value of nameof_atom is a string: the name of the identifier itself for the 
first case, or of the identifier after the dot for the second case. The string 
value is semantically identical to a literal for the same string, so `nameof 
foo.bar` and `"bar"` should be compiled to identical code. There is no 
difference to Python, only to human readers—and at least two classes of 
automated tools.

A refactoring tool should assume that `nameof self.spam` needs to change when 
`spam` is renamed.

A static type checker may be able to 

A static type checker may perform additional checks. If it can tell that the 
identifier, or the primary of the attributeref, does not match any accessible 
local or global (or bulltin) variable, or if the primary of the attributeref 
does match a variable with a type that specifies its attributes and the 
identifier of the attributeref does not match any of those attributes, an error 
should be reported. If the type checker cannot tell the type, or the attributes 
of that type, the checker may report an error or a warning or nothing. If the 
type is explicitly Any, or if it’s determined to be some type intended to have 
dynamic attributes (like SimpleNamespace, or a bridge or proxy), the checker 
should not report an error.

_______________________________________________
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/4GWYKCEVW3XUU52JAGXXGC3DEFYDODJM/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to