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/