
I have worked with both C# and Python for a while now and there is one feature of C# I'm missing in the Python language. This feature is the "nameof" operator. (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/...). The place I use this the most in C# is in `ToString()` methods or logging messages. This makes sure the developer cannot forget to update the name of a member. As an example I created this `Person` class. ``` class Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f"Person(name: {self.name}, age: {self.age})" ``` With the `nameof` operator this would look like the following: ``` class Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f"{nameof(Person)}({nameof(self.name)}: {self.name}, {nameof(self.age)}: {self.age})" ``` What do you think about this?

On Tue, Jan 21, 2020 at 1:49 PM Johan Vergeer <johanvergeer@gmail.com> wrote:
We can get the name of the class with "type(ins).__name__". If you want to get the names right it would be easier to loop over a list of strings and use 'getattr' on them, which would mean you only have to change the name in one place rather than two.

Isn't the name of the class more reliably `type(ins).__qualname__`? At any rate, I've actually wished for a shortcut to the name of an object's class- of the name of the class object itself- many times in the past. Mostly when writing reprs and exception messages. Not sure if that is in line with OP's suggestions. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Tue, Jan 21, 2020 at 2:03 PM Todd <toddrjen@gmail.com> wrote:

On Tue, Jan 21, 2020 at 02:25:56PM -0500, Ricky Teachey wrote:
Isn't the name of the class more reliably `type(ins).__qualname__`?
Depends on whether you want the plain old name of the class, or the qualified name of the class.
At any rate, I've actually wished for a shortcut to the name of an object's class- of the name of the class object itself- many times in the past.
Write a one-line helper function that returns type(obj).__name__ or __qualname__, whichever you prefer.
Mostly when writing reprs and exception messages. Not sure if that is in line with OP's suggestions.
No. As far as I can tell, Johan wants to capture the name of a name binding, not the name of a class. For example, given: x = 1 then you want nameof(x) to return 'int' (the name of the class) and Johan wants it to return 'x' (the name of the variable). But what should these things do? x = y = z = 1 nameof(1) nameof(z) nameof("Gumby") nameof(mysequence[0]) It isn't clear what precisely counts as the name of a variable. Johan's nameof operator looks like a function. But it can't be a function, for obvious reasons. Or at least, they're obvious to me, I don't know if Johan understands why a regular function can't easily/efficiently/unambiguously return the name of an object. Johan, it would be nice when making a proposal if you spelled out precisely what you expect it to do, as well what you don't expect it to do, especially if we don't know you well enough to predict if you are an expert or a novice. Otherwise we risk either talking down to you, or talking over your head. So for obvious reasons, nameof() cannot be a regular callable object. It has to be some sort of magic behind it so that if we write this: x = y = None nameof(x) nameof(y) the first call returns "x" and the second call returns "y", even though both objects are identically None. Fortunately we can already do this from Python today, using special variable quoting syntax. Instead of writing `nameof(x)`, just replace the function call with quote marks, and at compile time Python will compile in the name of the variable 'x' as if by magic. And best of all, quoting a variable name in this way is only two keypresses instead of ten. (It also works with double quotes too.) /deadpan Okay, I'm kidding, but only a little bit. Nevertheless, `nameof` is not an ordinary function, and it shouldn't look like an ordinary function. I don't buy Johan's argument: "This makes sure the developer cannot forget to update the name of a member." Of all the millions of places one might use an attribute, and forget to update it in the source code, only a tiny proportion will be guarded by a call to nameof. And even then, there will be cases -- quite common cases -- where one might forget to update the name inside the nameof() call, and not get an exception. For instance, I've frequently refactored names where I've ended up swapping two names. I can't think of an example off the top of my head right now, and I don't feel like trawling through years of history to find one, so I'll make one up: the variable "spam" is renamed to "eggs" and the "eggs" variable is renamed to "spam" Now if you refer to both: header = f"1:{nameof(spam)} 2:{nameof(eggs)}" # and some lines of code later on... line = f"1:{spam} 2:{eggs}" it's easy to swap the names in one place but not the other. I've done this more times than I care to admit to, and nameof() wouldn't have saved me. The bottom line is this: this has only a narrow use-case ("I need to print the name of a variable or attribute") and even in those use-cases, you still have to update the variable name in two places regardless of whether you write: # needs to be refactored to "eggs", eggs "spam", spam or # needs to be refactored to nameof(eggs), eggs nameof(spam), spam The second version may have the advantage that it will fail with an exception, instead of silently outputting the wrong string. But only sometimes. Which brings me back to my half tongue-in-cheek response about quoting variables with quote marks... as I see it, the easiest way to get this "nameof" operator to work is a source code transformation. The interpreter could simply do a compile-time replacement: nameof(spam) -> "spam" nameof(self.eggs) -> "eggs" nameof(None) -> "None" nameof(123) -> "123" or whatever semantics we desire. Seems like a lot of effort in adding this to the language, testing it, documenting it, dealing with the invariable problems when somebody uses "nameof" as a regular variable or function, etc etc etc, when we can just tell people: If you want the variable name as a string, use a string. And pay attention to what you are doing when you rename things. -- Steven

On 22/01/2020 12:03, Anders Hovmöller wrote:
He was pretty clear in saying he wanted the same thing as in C#. That no one in this thread seems to have looked that up is really not his fault in my opinion.
Oh, plenty of people have looked it up. The problem is that it relies on part of the nature of C# (variables are lvalues) that simply isn't true in Python, which I don't think the OP realised. -- Rhodri James *-* Kynesim Ltd

On 1/22/20 7:08 AM, Rhodri James wrote:
Or to expand on that, in C# and related languages, variable names actually HOLD some value (which might be a special type of value called a pointer), and a given object will either be in a specific variable name, or off somewhere in the heap with no name. We might have a variable with a pointer value to another object, and there it can be useful to query the object through that pointer and ask what is the name of the variable you are in, as we might not know it at the site of usage. In Python, variables don't hold values, but refer to them. A given value can easily be referred to by many names equally, and there is no such thing as a pointer (which gets you to a name) only multiple references to the same object. Thus nameof(x) can ONLY be "x" in Python (or an error is x isn't something that is a name), as at best x is referring to some object, but that object doesn't have a special name to refer to it that is its holder. Yes, one example where that linkage might be useful is it documents in the code that the string value is actually supposed to be the name of the variable, so a refactoring that changes the variable should change the string too, such a semantic link between a variable and its spelling is ill advised, and would only be used in a debugging environment with something like print("x", x) or some similar purpose function, and in that context, such prints should not normally be long lived or are part of long term logging in which case the stability of the label might actually be preferred to not break parsers for the log output. -- Richard Damon

Does it? How? https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/... seems pretty clear to me that it's a rather simple extraction of an AST node, lvalue or not doesn't seem relevant at all. Can you point me to something where this isn't the case? / Anders

On 1/22/20 8:05 AM, Anders Hovmöller wrote:
The part from the C# docs that people perhaps overlooked is that nameof is a compile-time function. It has access to the variable's name not just its value. Definitely, a runtime-function in Python has enormous challenges in trying to replicate this behavior. Not that I'm advocating adding something like this... --Ned.

On Wed, Jan 22, 2020 at 5:48 AM Johan Vergeer <johanvergeer@gmail.com> wrote:
Some objects (including types) have "inherent names", which can be accessed using the __name__ attribute: def __repr__(self): return f"{type(self).__name__}(... etc ...)" I'm not sure how this compares to what nameof(Person) should return, but the above idiom (or something like it) is very common in Python, as it allows repr to acknowledge a subclass. If you create "class Martian(Person): pass", then a Martian's repr will say "Martian". On the other hand, if you actually want "the name of the surrounding class", then that can be spelled __class__.__name__, and that will always be Person even if it's been subclassed. Not nearly as common, but available if you need it. For the attributes, though, there's no inherent name (at least, I presume self.name is a string and self.age is some sort of number). You CAN do some neat tricks with f-strings: return f"{self.name=}" but that would include "self.name" rather than simply "name", which I think is what you want. I would suggest creating a helper function that takes a list of attribute names, loops over them, and grabs the attributes. Using getattr in a loop is going to be less error-prone than your proposed form, which still has to have the word "age" repeated twice. Hmm. Maybe this should be a recipe in the docs, or something: "how to make a repr that reconstructs an object". def describe(obj, attrs): attrs = [f"{a}={getattr(obj, a)!r}" for a in attrs] return f"{type(obj).__name__}({", ".join(attrs)})" def __repr__(self): return describe(self, "name age spam ham location".split()) This comes up often enough that I think it'd be a useful thing to point people to. ChrisA

On 01/21/2020 11:25 AM, Chris Angelico wrote:
I'm not sure what you mean, but: --> class Person: ... def __init__(self, name): ... self.name = name ... def __repr__(self): ... return '%s(name=%r)' % (self.__class__.__name__, self.name) ... --> class Martian(Person): ... pass ... --> p = Person('Ethan') --> m = Martian('Allen') --> p Person(name='Ethan') --> m Martian(name='Allen') (Same results with f-strings. Whew!) -- ~Ethan~

On Wed, Jan 22, 2020 at 9:04 AM Ethan Furman <ethan@stoneleaf.us> wrote:
Yes, that's exactly what I mean, and exactly why self.__class__ is used here. If you actually want "Person" even if it's actually a Martian, you can use __class__.__name__ rather than self.__class__.__name__ to get that. ChrisA

On 1/21/20 1:42 PM, Johan Vergeer wrote:
def __repr__(self): return f"{nameof(Person)}({nameof(self.name)}: {self.name}, {nameof(self.age)}: {self.age})"
I'm trying to understand what you are looking for. Why isn't the above line just: return f"Person(name: {self.name}, age: {self.age})" That is, instead of "{nameof(self.name)}" just use "name"? You had to type "name" in your string anyway. How would nameof be helping here? --Ned.

I believe Python 3.8's '=' f-string specifier ( https://docs.python.org/3/whatsnew/3.8.html#f-strings-support-for-self-docum...) combined with __name__ does what you'd want: return f'{self.__class__.__name__}({self.name=}, {self.age=})' Outside of the __name__ dance, this is a bit more concise (and IMO readable) than C#'s nameof. On that note, for simple classes like this, namedtuples or 3.7's dataclasses would serve the purpose a bit more nicely. On Tue, Jan 21, 2020, 12:51 PM Johan Vergeer <johanvergeer@gmail.com> wrote:

Why? That looks like more code to accomplish exactly the same thing. On Tue, Jan 21, 2020 at 1:49 PM Johan Vergeer <johanvergeer@gmail.com> wrote:
-- CALVIN SPEALMAN SENIOR QUALITY ENGINEER cspealma@redhat.com M: +1.336.210.5107 [image: https://red.ht/sig] <https://red.ht/sig> TRIED. TESTED. TRUSTED. <https://redhat.com/trusted>

On Jan 21, 2020, at 10:48, Johan Vergeer <johanvergeer@gmail.com> wrote:
What would the semantics of nameof be in Python? Would it just be lambda obj: obj.__name__? Or some fancy inspect-module style chain of “try this, then that, then the other”? Or does it need to look at the compiled source code context or something? Unless it’s the last one, can’t this just be a normal function rather than a special operator? And if so, why does it need to be in the stdlib, much less a builtin, rather than just a function you stick in your toolkit or install off PyPI? I have two functions that I use that are basically obj.__name__ and type(obj).__name__ that I just import or copy-paste whenever I’m writing a lot of classes that need a repr, which seems to be exactly your use case, and I’ve never been bothered by doing that, much less considered that maybe it’s worth having either one as a builtin, before now.

On Jan 21, 2020, at 13:32, Andrew Barnert <abarnert@yahoo.com> wrote:
Sorry; I didn’t notice the nameof(self.age) part there. That definitely does need to look at the source (or something else, like the bytecode), because whatever value is in self.age doesn’t know that it’s in self.age (especially since it’s probably in lots of other variables as well); all it knows is that it’s the int object with value 42. But it seems like nameof(self.age) always has to be just “age”, which you already have to type inside the nameof if you want it to be findable, so it’ll never be useful. Anywhere you could write `{nameof(self.age)}` you could just more simply write `age`. The big difference in C# is that variables are lvalues. In Python, self.age is just a reference to that int object 42 somewhere; in C#, this.age is a reference to the int-sized, int-typed location 8 bytes after the start of “this” (which can decay to the int value stored there on demand), and the runtime can use that to figure out that it’s the “age” attribute of this via reflection (or maybe the compiler can do that). This also means you can pass around a reference to this.age and mutate this through that reference (and presumably nameof works on that reference too), which doesn’t make any sense in Python.

On 21 Jan 2020, at 22:50, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
But it seems like nameof(self.age) always has to be just “age”, which you already have to type inside the nameof if you want it to be findable, so it’ll never be useful. Anywhere you could write `{nameof(self.age)}` you could just more simply write `age`.
That misses the point. Refactoring tools for example won't know how to handle the rename of the variable foo in this example: foo = 1 n = 'foo' print(n, foo) If you had n = nameof(foo) It would know what to do. That's why this feature exists in C# and AFAIK also in Swift for example. / Anders

On 1/21/2020 4:32 PM, Andrew Barnert via Python-ideas wrote:
What would the semantics of nameof be in Python? Would it just be lambda obj: obj.__name__? Or some fancy inspect-module style chain of “try this, then that, then the other”? Or does it need to look at the compiled source code context or something?
I think some wrapper around inspect.getmembers() would be the easiest/best thing to do. dict(inspect.getmembers(obj))['__name__'] With some error checking for the KeyError if inspect.getmembers can't get a name for the object you passed in. There are probably more performant ways to write this, but this was my easy one-liner version. Eric

On 1/21/2020 4:50 PM, Eric V. Smith wrote:
And in case it's not clear, my point is: Many things in Python don't have have names. For those that do, the inspect module knows about them, so use it. And if there's something that has a name that inspect currently doesn't recognize, then if we fix inspect to understand the name of that object, everyone who uses inspect would win. Eric

On Tue, Jan 21, 2020, at 16:32, Andrew Barnert via Python-ideas wrote:
The C# version becomes a string constant and doesn't have to look at anything other than the expression itself. It is the literal name of the variable [or attribute] in the expression, irrespective of its value. The intent is for it to be a string literal that survives refactors, so you could do nameof(a_person.age) and that would compile down to "age" [without actually performing an attribute access. C# allows you to do this with instance members without making an instance, but it is unclear what the best way to do this in python would be], but if you used a refactoring tool to rename the age attribute, it would change this expression along with all of the other places it is used, to give it the new attribute name. There's no fancy run-time lvalue reflection stuff going on as you suggested in your other post, it is just the name from the expression, as a string constant. It is purely a compile time operation (which is why it has to be an operator, not a function)

Thanks everyone for your responses. I would like to take all the information you gave me and do some research on it. I'll try to get it done this weekend or beginning of next week.

It is a couple of days later, but I managed to create a more expanded proposal. This proposal is about having a simple and consistent way of getting the name of an object. Whether it is a class, type, function, method or variable or any other object. # Why? ## Usage in strings The first situation this could be used is in strings (for example in `__repr__`, `__str__` and `print()`) I've come across too many situations where the developer made a typo (which is usually the developer is a hurry or just having a bad day) or in the case of a refactoring where the developer didn't rename the object in the string representation. To be honest, I am a big fan of IDEs, like PyCharm, which have great refactoring tools, but it doesn't refactor strings. ## Usage in comparisons Another situation is when you want to do a comparison. An example of this would be: ```python def my_factory(class_name: str): if class_name == "Foo": return Foo() if class_name == "Bar": return Bar() ``` I know this is a very simple example that can be solved with the example below, but it would be nice if we can do the same with methods, functions and attributes. ```python def my_factory(class_name: str): if class_name == Foo.__name__: return Foo() if class_name == Bar.__name__: return Bar() ``` ## The Zen of Python The Zen of Python has a couple of items that apply to this one in my opinion: Beautiful is better than ugly. Simple is better than complex. Sparse is better than dense. Readability counts. **There should be one-- and preferably only one --obvious way to do it.** Although that way may not be obvious at first unless you're Dutch. # How? From the messages in this thread I concluded there is some confusion about what I would like to achieve with this proposal. In this part I will try to make it more clear what the behavior would be. For now I'll stick to the C# naming `nameof()`. ## Class names When you want to get the name of a class, you should just use the name. So `nameof(Foo)` becomes `"Foo"` and `nameof(type(foo))` also becomes `"Foo"`. The results are basically the same as `Foo.__name__` and `type(foo).__name__`. ## Function names When you want to get the name of a function, you would do the same you do with a class. ```python def foo(): ... nameof(foo) #Returns 'foo' ``` This is (again) the same as `foo.__name__` ## Attribute names You should be able to get the name of an attribute. ```python class Foo: bar: str = "Hello" def __init__(self): self.baz = "World" def __str__(self): return f"{nameof(self.bar)}: {bar}, {nameof(self.baz): {baz}}" # Returns "bar: Hello, baz: World" foo = Foo() nameof(foo) # Returns "foo" nameof(foo.bar) # Returns "bar" ``` As Chris Angelico suggested we can already use a special syntax for f-strings which is pretty cool, but it has the limitation that we have less control over the output. ```python return f"{self.name=}" # returns `self.name="something"` ``` ## Invalid usage There are also situations that will return an error. ```python nameof(1) nameof("foo") nameof(["bar", "baz"]) ``` ## Stuff to think about There are also situations that I haven't been able to make a decision about and I think these should be discussed further down the road. ```python nameof(None) nameof(type) nameof(int) _foo = Foo() nameof(_foo) #Should this return "_foo" or "foo"? ... ``` ## How should the interpreter handle it? I think the interpreter should handle it as anything else that is passed to a function, so when the value passed to the `nameof()` function doesn't exist, an error should be thrown. # How can this be built in the Python language (or a library) Some people responded this will be very hard to implement because of the way Python is built. To be honest, I don't know nearly enough about the internals of Python to make a solid statement on that. I also don't know how the new f-string syntax `f"{self.name=}"` works under the hood, but it does give me the impression that implementing this proposal should be possible. # What about `__name__`? Most of the examples I wrote above can be solved by just using `__name__`, which solves most use cases, except for variable and attribute names, which cannot be resolved right now because objects don't have names. So when we want to follow `There should be one-- and preferably only one --obvious way to do it.` it would be better to use `__name__` on an object, but I believe that would cause breaking changes. What I mean is: ```python class Foo: ... foo = Foo print(foo.__name__) # Prints "foo" foo = Foo() print(foo.__name__) # Throws AttributeError: 'Foo' object has no attribute '__name__' ```

On Jan 30, 2020, at 11:20, Johan Vergeer <johanvergeer@gmail.com> wrote:
I think this is glossing over something very important. You really aren’t trying to get the name of an object at all, you’re trying to get the name of a _variable_. After you write foo.bar = 2, the object in foo.bar is just the number 2, an object of type int that’s probably the same object that’s referenced in dozens of other places, both named and anonymous, in your program’s current state. It can’t possibly have the name “bar”. What _can_ have the name “bar” is the variable that references that value. But that variable isn’t a thing that exists in Python at runtime. A compile-time transformation could convert nameof(foo.bar) into “bar”. In fact, the compiler already pretty much has to do exactly that to emit the code for foo.bar, which is effectively 'push the object in too, then push the string “bar”, then do an attr lookup with those two things'. So nameof cannot be a function. It has to be a special compiler-time operator. The code emitted for nameof(foo.bar) has to be effectively the same code emitted for the literal “foo”. And this affects a whole lot of your other points below:
The way you already do this today is usually to look up the class name in a dict—either directly, or as part of a namespace lookup (e.g., getattr(self, class_name)). Having nameof wouldn’t really help here. However, it could help on the _caller_ side: you could call my_factory(nameof(Foo)). In this trivial case, there’s no reason for that, because if you have the name Foo you already have the class object Foo and don’t need a factory in the first place. But there might be less trivial cases where it might be useful.
I know this is a very simple example that can be solved with the example below, but it would be nice if we can do the same with methods, functions and attributes.
But you can already write that factory that way. Methods are attributes, and both can be looked up with getattr. Functions are attributes of the module object, and members of globals, so they can be looked up either way. You don’t need nameof for this kind of dynamic lookup, and it doesn’t help to add it. You only need nameof got static (compile-time) lookup, to serve the purposes from your initial paragraph, like making sure the name gets caught by refactoring tools (which can be sure that nameof(Foo) must rename along with Foo, but can’t know whether the string literal “Foo” needs to change).
So what happens here: class Foo: pass Bar = Foo print(nameof(Bar)) If you compile nameof(Bar) into a call to a normal (runtime) nameof function that returns param.__name__, you’re going to print out Foo. If you compile it to just Bar.__name__, you’re still going to print out Foo. If you compile it to the string "Bar", you’re going to print out Bar. And I think that’s what you actually want here. Meanwhile, I don’t see how nameof(type(foo)) can work. At compile time, we have no idea what the type of foo is. Consider this case: foo = Foo() if spam else Bar() Even if the compiler were smart enough to know that Foo and Bar are guaranteed to be names for the same object (which they actually might not be even after Bar = Foo—you can write a globals dict whose __setitem__ does something crazy… but ignore that), it still can’t know which name we used here without knowing the runtime value of spam, which it can’t possibly have. As a side note, this implies that making nameof look like a function call (with parentheses around an argument) is misleading. Everything that looks like a function call in Python is actually compiled as a function call, and I don’t think you want to break that. And there’s no real reason to—Python already has spelled-out prefix operators like not, so why shouldn’t nameof be the same? (In C# things are different.)
If you compile nameof(foo.bar) to a function call, that function gets called with the string "Hello". There’s no way you can get anything else out of that string at runtime. (You can use horrible frame hacks to inspect the caller’s context and try to guess what it was trying to pass you, which will work in many cases, but if you’re proposing a new language feature why make it depend on that?) What you want to compile this to is pretty clearly just the string “bar”. Which is immediately available at compile time. You do need to go through the whole grammar to decide exactly what productions you should be able to use in a nameof and what the result should be. But that shouldn’t be too hard. (And it’s a necessary first step toward an implementation anyway.)
Why should these be any different from anything else? For type and int, these are just names like any other (except for usually being found in builtins rather than the module’s globals), and the things they name are types like any other. (They’ve even got a __name__ like other type values.) None is a bit special because it’s sort of a keyword to prevent people from accidentally rebinding the name to a different value, but other than that it’s still basically just a builtin name, and the thing it names is a value no different from “hello” or 2 in your other examples.
_foo = Foo() nameof(_foo) #Should this return "_foo" or "foo"?
How could it possibly return “foo”? Unless you’re suggesting that the occasionally-followed convention of naming a generic instance of a type with the lowercase version of the type’s name should be enshrined in the language?
## How should the interpreter handle it?
I think the interpreter should handle it as anything else that is passed to a function,
But it can’t be.
so when the value passed to the `nameof()` function doesn't exist, an error should be thrown.
But you can’t know that at compile time. This is actually the biggest problem. In C#, the compiler has to know the names of every variable, attribute, etc. In Python, it can’t. There’s nothing stopping me from doing this: if spam: foo = Foo() … and now the variable foo may or may not exist. Or I can even do this: globals()[name] = 3 … and if name happens to be holding the string “foo” then foo will exist. There is a special case here related to local variables, but if you want this to work for globals and attributes (which I assume you do, because all of your examples are globals or attributes) that isn’t relevant.
You don’t need to know the internals, at least if you can convince someone who _does_ know the internals to do the work for you. But you do need to know the basics of what variables are in Python as opposed to C#.
That’s not right. Classes and functions are objects, and they have names. But the real issue is that you don’t _want_ the name of the object, you want the name of the variable. And no object knows the name of the variable you used to access it. Even for classes and functions, the fact that class statements and def statements happen to produce a variable with the same name that’s stored in the object doesn’t mean you want the name stored in the object, because it’s trivial to create a different name for the same object (assignment, argument passing, import as, …), and when you do, it’s that different name that you want.

On 2020-01-30 7:17 p.m., Andrew Barnert via Python-ideas wrote:
Consider: x=nameof(foo.bar) in today's python becomes: foo.bar x="bar" and when running this you get an AttributeError or something. the benefit is that "bar" is only typed once, and the attribute access (and thus error-raising code) is tied to the resulting string. either you change both the attribute access *and* the resulting string, or you get an error. (correct me if I'm wrong.)

On Jan 31, 2020, at 11:01 AM, Soni L. <fakedme+py@gmail.com> wrote:
One issue I am seeing is that x = nameof(foo.bar) is crossing the line between compile time and run time behaviors. The resultant string, “bar” needs to be generated at compile time, but the operation still needs to do a check at run-time to determine if that IS the right result, as if foo doesn’t have a bar attribute it needs to raise an error instead.

On 1/02/20 6:15 am, Richard Damon wrote:
I don't think I would bother with the runtime check. This is mostly going to be used in a context where you're writing out the same thing again to get its value, e.g. print("The value of", nameof(foo.bar), "is", foo.bar) This can be translated to print("The value of", "bar", "is", foo.bar) and you'll still get an AttributeError if foo doesn't have a bar attribute. -- Greg

On Jan 31, 2020, at 08:03, Soni L. <fakedme+py@gmail.com> wrote:
That does work, but that means foo.bar has to exist and have a value before you look up the name. Consider these cases: class Spam: def __init__(self): self.eggs = 42 print(nameof Spam.eggs) # AttributeError class Foo: pass foo0 = Foo() setattr(foo0, nameof foo0.bar, 42) # AttributeError foo1 = Foo() print(nameof foo1.bar) # AttributeError foo1.bar = 42 foo2 = Foo() if spam: foo2.bar = 42 print(nameof foo2.bar) # AttributeError if not spam foo3 = Foo() Foo.bar = 23 print(nameof foo3.bar) # works fine baz = MyRPCProxy(baseuri, endpoint) print(nameof baz.bar) # makes a remote procedure call on the server and ignores the result or raises AttributeError depending on the server These all seem more confusing than helpful—and very different from C#. If you explain that nameof is a mix of compile time and run time, or just explain that it compile to the same thing as the code as you gave, people could figure it out, but it still seems both weird and undesirable. Python variables just don’t have a static type, and even if they did, the attributes are dynamic rather than determined by the type anyway. And that isn’t some edge case that occasionally comes up; that Spam example is the usual ordinary way for a class to give its instances attributes.) However, that does raise the possibility that maybe mypy (or your IDE or favorite other static type checker tool) should be doing the check, because Python variables often do have a static type and it often does declare the variables and “often” may not be good enough for language semantics but it’s exactly the point of optional gradual type checking. So: @dataclass class Spam: eggs: int = 42 spam.cheese # If your typing-aware IDE will flag this nameof spam.cheese # … it will do exactly the same here Now, when you’re using mypy/etc , nameof is just like C#, and gives you exactly the desired benefits, but all the Python compiler has to do is emit “cheese”. And when you aren’t using mypy? Then it just doesn’t get checked. Same as all other static typing errors. What happens if spam: Any, or if spam: Spam but Spam didn’t statically deflate its attributes? At first glance, given the way optional gradual typing generally works, this shouldn’t be an error. But if we think of nameof as a compile time operator that’s meant to act like C#, maybe it is a static typing error to use it on an attribute that can’t be statically checked? Or maybe a warning? I don’t know. Maybe that should even be left up to the type checkers as a QoI issue rather than defined by Python?

On 2020-01-31 2:36 p.m., Andrew Barnert wrote:
All of these seem to be working exactly as I'd expect nameof to work. In fact these are exactly how I'd prefer it to work, personally. I'm not OP tho.
baz = MyRPCProxy(baseuri, endpoint) print(nameof baz.bar) # makes a remote procedure call on the server and ignores the result or raises AttributeError depending on the server
Yes. I know.
But here's the thing -- C# is statically checked. Python is dynamically checked. (and yes, Python *does* have type checking, among other things.) I figured this would be the correct way to adapt a statically checked syntactic construct into an *equivalent* dynamically checked syntactic construct. The static construct has: - Errors at compile-time if stuff gets incorrectly refactored The dynamic construct has: - Errors at runtime if stuff gets incorrectly refactored And this goes for anything you can contrast between static and dynamic constructs: classes, methods, everything. They always take a compile-time error and turn it into a runtime error. I strongly feel like it should be the same here.

On Jan 31, 2020, at 14:51, Soni L. <fakedme+py@gmail.com> wrote:
All of these seem to be working exactly as I'd expect nameof to work. In fact these are exactly how I'd prefer it to work, personally. I'm not OP tho.
Really? These seem like exactly the kinds of places I’d want to use nameof (so the IDE can magically refactor for me), and I can’t do that if it raises exceptions at runtime instead of working. It only seems like the right thing for the trivial case that, as Greg Ewing says, would already work fine without a check anyway.
Not so much. You _can_ do dynamic type checking in Python, but 80% of the time you don’t, you just accept anything that quacks as the right type. In C#, if you pass a complex or a string to a function that wanted an int, you get a compile-time type error. Python doesn’t have any equivalent runtime error, unless you manually write code to check isinstance and raise. And even that can’t handle all types that really exist in Python—there is no way to tell if something is an Iterator[int] for example. Of course if the function tries to return param+1, that will raise a TypeError if you passed a string—but not if you passed a complex. And attributes are if anything even more “ducky” than function signatures. While you _can_ restrict the set of attributes for instances of a type with a custom __setattr__ or with __slots__ or whatever, usually you don’t; most classes’ instances can have whatever attributes they want.
I figured this would be the correct way to adapt a statically checked syntactic construct into an *equivalent* dynamically checked syntactic construct.
But it’s not equivalent. In all those examples I gave, you statically know whether foo.bar exists, and therefore the compiler can check that nameof is correct, but you dynamically don’t know, so the runtime cannot check that nameof is correct. It could check something significantly different, and less useful, but it can’t check the equivalent thing, because there _is_ no equivalent thing to “Foo instances have an attribute named bar” in Python, even at runtime.

On 2020-02-01 12:00 a.m., Andrew Barnert wrote:
Yes, really. It's dynamic, so it must pay attention to the context it's being used in.
Okay here's one of the examples you gave: class Spam: def __init__(self): self.eggs = 42 print(nameof Spam.eggs) # AttributeError I don't know how C# does it, exactly, *but I'd expect this to be an error!* C#, Java, etc have the concept of static vs instance variables. I'd expect referring to an instance variable from a static context (such as this nameof Spam.eggs) would result in an error. Additionally those languages have null, so you could do something along the lines of: Spam dummy = null; nameof dummy.eggs if you really wanted to. But arguably you shouldn't, because you're doing it in the wrong context (class vs instance). IDEs are very much capable of refactoring strings. On the other hand, runtime errors would benefit those of us who use e.g. plain vim and no IDE. I don't use an IDE. thankfully the general case is that you get runtime errors where you forget to refactor something. but sometimes, you don't. and that's where this would fit in IMO. so I'm gonna say this proposal is completely, 100% useless for IDE users. if your IDE doesn't do quite what you want, you should add an extra plugin or two to make it do so. but this feature would be a huge win for ppl who don't use IDEs. like myself.

On Jan 31, 2020, at 19:30, Soni L. <fakedme+py@gmail.com> wrote:
Why? The name of a variable does not depend on its runtime context. Which is a good thing, because by the time you get to that runtime context you don’t even _have_ a variable; there is no such thing as variables in the Python data model.
I don’t think it is. I don’t have a C# compiler handy, but from the spec (sadly the “examples” section is just “TODO”…):
The meaning of the named_entity of a nameof_expression is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.
…
A nameof_expression is a constant expression of type string, and has no effect at runtime. Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed
So an instance member in a static context is not an error, and the value is the name of the member, unless I’m reading something wrong. Also, this is the same way operators like sizeof, type of, and offsetof work in C#, C++, and C, isn’t it?
How is that relevant? Clearly the result should be the string “eggs” in C#, right? And in my static-only version of the proposal, the same would be true in Python, but in your version it would be an error. And a refactoring tool should rename this eggs when the member is named, which is the whole point of the proposal. So why is doing something different from C# that breaks the point of the feature better?
IDEs are very much capable of refactoring strings.
No they’re not. They have to guess at it using heuristics, which are complicated, and often get it wrong. Because it’s inherently ambiguous whether the string or substring “spam” is meant as the name of an attribute or as normal English text.
On the other hand, runtime errors would benefit those of us who use e.g. plain vim and no IDE.
I mostly use emacs rather than an IDE. But I can still use refactoring tools. There’s nothing about a refactoring tool that demands that it be built into an IDE just because it could be—in the same way that PyCharm integrating a static type checker doesn’t stop me from using mypy.

On Thu, Jan 30, 2020 at 07:17:34PM -0000, Johan Vergeer wrote:
Variables are not objects, and in Python, there are two distinct meanings for "name": (1) "Names" in the sense of name bindings like `spam = expression`. In this sense, objects can have zero, one or more names: # this string has (at least) three names spam = eggs = cheese = "Hello world!" but the *name* "spam" is not an object or a first-class value at all. (2) Some objects, like modules, classes, functions and methods, have a special dunder `__name__` attribute. When people talk about the name of a module, class, function or method, that's what they expect, and that's what they see in the object repr. Most objects have no such concept of a name in sense (2), and most objects are not bound to a name in sense (1). Objects which have both may not agree: def spam(): pass eggs = spam del spam What is the name of the function object bound to the "eggs" name? Should it be "eggs" or "spam"? [...]
To be honest, I am a big fan of IDEs, like PyCharm, which have great refactoring tools, but it doesn't refactor strings.
You should report that to the IDEs as a feature request.
If I saw that code in production, I would strongly suspect that the author isn't very experienced with Python or is trying to write Java (or equivalent) code in Python. There are exceptions, of course, such as if you are getting the class name from user data at runtime. But normally that would be better written as: def my_factory(cls: type): return cls() (This is a toy. In real code, the my_factory() function better do something useful to justify its existence.)
In your earlier example, your sense of "name" is that of name bindings. In this example, your sense of "name" is the object's internal name. These are two different, distinct and independent concepts.
Spoken like somebody who is not used to languages where classes are first-class values. for obj in (Foo, Bar, Baz): print(nameof(obj)) Should that print "obj", "obj", "obj" or "Foo", "Bar", "Baz"? Trick question! Actually I did this earlier: Foo, Bar, Baz = Spam, Eggs, Cheese so perhaps it should print "Spam", "Eggs", "Cheese" instead. How does the nameof() function know which answer I want? The same applies to functions, modules and methods. -- Steven

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.

Sorry, sent early… ignore that and try this version.
On Jan 31, 2020, at 19:58, Andrew Barnert <abarnert@yahoo.com> wrote:
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 A second use is static type checkers. If a type checker sees `nameof spam.eggs`, it can apply whatever rules it would use for `spam.eggs` itself. For example, if it can figure out the type or `spam`, and that type declared its attributes, and there is no attribute named `eggs`, this can be a static type error. 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 automated tools. Compatibility: Because `nameof` is a valid identifier today, there may be code that uses it as a variable name. This means the usual 3-version __future__ schedule is probably needed. And a search through public code to make sure it isn’t a lot more common than you’d expect. Alternatives: Why no parentheses? Because in Python, only function calls take parentheses. In C# (where this feature originated) there are other compile-time operators like sizeof that take parens, and ultimately this goes back to making those operators look like calls to preprocessor macros in 1970s C; that isn’t relevant in Python, so requiring parens would just be confusing for no benefit. Why no runtime behavior? Because there’s nothing that could reasonably be checked. Unlike C#, Python doesn’t have “variables” at runtime; it just has names bound to objects in namespaces. Given an object, there is no way to know what name you used to access it. Also, Python attributes are completely dynamic—in C#, `spam.eggs` means something like “the int-typed value found between 4 and 8 bytes after the start of `spam` in memory”; in Python, it means “the result of calling getattr(spam, 'eggs'), which could be any arbitrary code”. Even if it were possible, it’s not clear what the benefit would be, and without someone making a case for a benefit, it’s not worth trying to come up with something clever in the first place.

Thank you so much for this concrete proposal. I could not have described it clearer myself. I'm not sure about leaving out the parentheses. But this is mostly out of preference. Especially since Python also has a `type()` function. I also thought about using `name()` instead of `nameof()` to be more consistent with that. I can also see your point of view though. Out of personal curiosity: Is the way you described the grammar an official notation, and if so, could you give me a link to some documentation?

But that’s the whole point: type is a function, and nameof is something totally different from a function. (Actually, type is a type whose constructor does something different from constructing an object when passed a single param, but never mind that bit.) Making it look like a function call makes sense for a C family language—function calls, macro calls, old-style annotations (like declspec in Microsoft C), and compile-time operators like sizeof all use the same syntax, and nameof is just like sizeof, so why shouldn’t it look the same? Making it look like a function call in Python wouldn’t make sense. In Python, while you can call all kinds of things (functions, types, objects whose types define __call__) with the same syntax, they always have the same semantics: at runtime, call the value on the left with the values of the things inside parens as parameters. Something with radically different semantics (that doesn’t even evaluate the value of the “parameter”) using the same syntax would be confusing.
Out of personal curiosity: Is the way you described the grammar an official notation, and if so, could you give me a link to some documentation
It’s the almost-BNF notation used in the Python docs. See https://docs.python.org/3/reference/introduction.html#notation for details. If you haven’t skimmed the reference docs, they do a pretty good job explaining the semantics that goes with each construction, the underlying data model, etc. in terms that make sense to Python programmers (as opposed to, e.g., the C spec, which is only intended to make sense to people writing C compilers).

On 1/31/20 10:58 PM, Andrew Barnert via Python-ideas wrote:
Thinking about this, I have a question, IS there existing a refactoring program that can do the rest of the job in Python well. I am not sure there can be. Take an example refactoring problem: We have a logging module to save diagnostic information about program operation. The logging class currently has a member log that we want to change to log_file. In a statically type language, this is fairly easy, scan through the source code, find all references to the symbol log, see if they refer to the logging module or something else (which is easily solvable in a statically typed language, as the compiler needs to do this) and if they refer to the logging module, change the reference. The refactoring program just needs about the same smarts as the compiler. We can't easily do this in Python. In general, we come to the sequence foo.log, in order to determine if we want to change this, we need to know what foo will be every time it gets there. To determine this we need to back track to figure every path of execution to here. In fact, the transformation may not be possible (or may require other changes beyond what we want) as there may be a usage that handles many different types, all that happen to have a log member, so to change one class, we need to change them all (this can also happen in C++ templates which also can use duck typing). This lack of local type information makes the refactoring MUCH harder, and as you make the program smart enough to work on handling this, including strings might not be that hard. My guess is that any such refactoring is going to need to ask the programmer about a number of cases of the usage that the program can't determine, and thus can include strings that match too. -- Richard Damon

People keep mentioning refactoring. It's a red herring. No refactoring tool needs a nameof operator added to the language in order to do its job. And certainly an operator that requires running the program in order to use it is not going to be helpful. Refactoring tools analyze the program; they don't run it. And f-strings are another red herring. There is nothing magical about expressions inside f-strings compared to those outside. Ignoring the red herrings, I see no utility in a nameof operator and no way for it to actually do anything useful. --- Bruce

On 2/3/20 12:02 AM, Bruce Leban wrote:
IF Python had a proper refactoring tool (see my other message where I question the ability to do that) then the nameof operator would clearly help keep logging/debug strings in line with the program definitions. A statement like print("bar", foo.bar) would be very hard to notice that the "bar" match the foo.bar, while print(nameof(foo.bar), foo.bar) makes the connection explicit. This is where such an operation could help with refactoring, having an actual Python attribute reference that the refactoring operation could see, so it knows that the string is based on that attribute and not something else. As I mentioned elsewhere, the issue is that in Python, if we change the attribute bar in class Foo, then we have the problem that we often can't tell if in foo.bar if foo is of type Foo, so we should apply the change. This isn't a problem is statically typed languages, as there we can determine the type of foo, and see if the change applies (at least in most cases). -- Richard Damon

To restate the motivation: the hope is that there is a potentially large benefit of being able to more easily refactor code with something like a nameof(). I am going to make the claim that: 1. this benefit is actually minimal and does not address a lot of other existing refactoring problems/chores, and 2. comes at the cost of a possible loss of readability, and therefore isn't worth the trade Consider the following typical code (I hope it is nice; I feel like I can certainly read it): import logging import functools class FunctionLogger: """Records use of a function. The optional `log` parameter is to be a callable that accepts a string. It is logging.info by default. """ log = logging.info def __init__(self, log=None): if log is not None: self.log = log def __call__(self, func): func_name = func.__name__ @functools.wraps(func) def wrapper(*args, **kwargs): try: self.log(f"called {func_name!r}") except: cls_name = type(self).__name__ logging.exception(f"failed to log {func_name!r} call; is {cls_name}.log set correctly?") finally: return func(*args, **kwargs) return wrapper Let's think through: what refactoring must occur to change the "log" parameter to something else? And, how readable does the code remain afterward? At least some of the code could certainly benefit from being more easily refactored (by an IDE) with nameof(), but how much? import logging import functools class FunctionLogger: # NOTE: this docstring will result in a runtime error, so can't even use nameof() here to help ourselves f"""Records use of a function. The optional `{nameof(FunctionLogger.log)}` parameter is to be a callable that accepts a string. It is logging.info by default. """ log = logging.info # no need for nameof() here, but see below * def __init__(self, log=None): # IDE will refactor the init signature SEPARATELY (see below *) if log is not None: # no help from nameof() in __init__ body # IDE will get this one just fine anyway; shouldn't use nameof() in this situation # using it actually hurts readability setattr(self, nameof(self.log), log) def __call__(self, func): func_name = nameof(func) # it's different, but NOT an improvement over func.__name__ @functools.wraps(func) def wrapper(*args, **kwargs): try: self.log(f"called {func_name!r}") except: cls_name = nameof(type(self)) # different, but NOT an improvement over type(self).__name__ log_param_name = nameof(self.log) # ok, HERE is a place we are definitely going to benefit from nameof() # readability of next line might actually be slightly improved...? But perhaps it's also worse...? # but the IDE will refactor next line automatically, which is handy. logging.exception(f"failed to log {func_name!r} call; is {cls_name}.{log_param_name} set correctly?") finally: return func(*args, **kwargs) return wrapper * For the class level member and init signature/body: the IDE won't know to include the class member and the init signature/body in a refactor of a member-level variable, and this problem isn't helped by nameof(). Multiple refactoring chores have to be completed to change the parameter name: 1. the init signature, 2. the class level variable, 3. object level variable, 4. the class docstring, 5. all of the f strings. Using a nameof() only totally prevents one of them (the f strings; it can't help with the docstring). So I guess there is SOME benefit here. But I think it comes at the cost of some potential loss of readability, and there are some major places in which nameof() doesn't bring any help at all (looking at you, class docstring). And there is a ready alternative: use a global if you think you might rename your parameters later (see code at bottom). This rolls TWO of the refactoring chores into one (the f strings and the docstring). *Bottom line: refactoring remains a chore. The win is minimal. Do nothing option is preferred.* import logging import functools _FOO = "foo" # haven't decided on .foo member name yet... class FunctionLogger: # with a global, this docstring will work! f"""Records use of a function. The optional `{_FOO}` parameter is to be a callable that accepts a string. It is logging.info by default. """ log = logging.info def __init__(self, log=None): if log is not None: self.log = log def __call__(self, func): func_name = func.__name__ @functools.wraps(func) def wrapper(*args, **kwargs): try: self.log(f"called {func_name!r}") except: cls_name = type(self).__name__ # employ the global below for the error message, mischief managed logging.exception(f"failed to log {func_name!r} call; is {cls_name}.{_FOO} set correctly?") finally: return func(*args, **kwargs) return wrapper --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

On Feb 3, 2020, at 03:59, Richard Damon <Richard@damon-family.org> wrote:
This is the same as Smalltalk, ObjC, Ruby, f-script, and all of the other languages that use the same dynamic type/data model as Python. And Smalltalk was the first language to have practical refactoring tools (although I don’t think they were called that until Ralph Johnson’s refactoring object browser in the early 90s). One difference between Python and most of the other Smalltalk-model languages is that they use symbols or selectors or some other string-like type to name methods, while Python uses plain old strings. If you have print(:bar, foo.bar) obviously bar is the name of an attribute rather than normal text. Dropping selectors from the language turns out to cause a lot fewer problems than any Smalltalk devotee would have believed, just a few very small problems—like the one nameof is trying to fix. Meanwhile, unlike Smalltalk and most other languages with the same model, Python has optional static typing. The other major Smalltalk-model language that added optional static types is ObjectiveC—and one of the reasons was to improve the navigation and refactoring tools. For example, if you have a function that takes a `foo: Any` param (spelled `id foo` in ObjC) and there are three unrelated types that all have a `bar` method, the tool will tell you that it’s ambiguous which one you meant by `nameof bar` (spelled `@sel(bar)`), and it can suggest that you either specify a type for `foo`, or create an implicit ABC (a `@protocol` in ObjC terms) to own the method. If you do the first, renaming Foo.bar to baz will change the selector; if you do the latter, it will warn you that Foo.bar makes Foo conform to the Barable protocol that you defined and there are selectors in your program that depend on it being Barable, so do you want to break that or do you want to rename Barable.bar and all of the classes that implement it instead? If you do neither, it doesn’t guess, it tells you that there are two ambiguous uses of the selectors and lets you see the two uses of the selector or the three classes that define it, so you can proceed manually. Of course this means that an IDE, object browser, or standalone refactoring tool has to build a mapping from selector names to a list of implicit uses, explicit uses, and definitions (including knowing which definitions are inherited, and which are relied on by protocols) for the whole program. But that’s exactly what they do. That’s why RJBrowser takes a while to start up, and why Xcode is constantly running clang on bits of your code in the background as you edit. Couldn’t a Python tool just also keep track of every string and substring that has at least one match as a use or definition of an attribute? Yes. But I think it’s obvious why this is a lot more work and at least a little less useful. And that may be part of the reason Python has always had fewer refactoring tools available than Smalltalk, ObjC, etc., which is why nameof could be a useful addition.

On Feb 3, 2020, at 10:25, Andrew Barnert <abarnert@yahoo.com> wrote:
All that being said, I’m not sure _how_ useful it would be in practice. Python has a chicken-and-egg problem that C#, ObjC, etc. don’t. If the C#/ObjC devs add a new feature to their language, the Visual Studio/Xcode team next door adds a nameof-driven renaming feature to the refactoring tools in the IDE that 90% of C#/ObjC programmers use, and then then everyone who wants that feature starts using nameof. If the Python devs add nameof, PyCharm, PyDev, etc. may not take advantage of it, and they may already have an often-good-enough heuristic-guessing feature for people who don’t use it. If not many people start using it, there will be even less motivation for PyCharm to take advantage of it, etc. If a new feature has an obvious large benefit (and/or is fun enough to implement), like optional static typing, you can jump past that hurdle. If a new feature has other uses even without IDE support, like @dataclass, you can spiral over it. But nameof is neither; it might just be a dead-on-arrival feature that’s only ever used by a handful of large teams who build their own internal tools. (And that large internal-tool-building team could just define a builtin `def nameof(x: str): return x` to use while debugging and write an install-time or import-time transformer that just replaces every `nameof(x)` with `x` to eliminate the deployed runtime cost.) Add in the fact that most people use the newest version of C# or ObjC for any new project, while Python developers often stay a version or 3 behind, and a breaking change like this would probably need a __future__ and/or deprecation schedule on top of that, and the problem looks even worse. So, someone who wants this feature has to not only resolve all the confusion over what exactly is being proposed and how it helps, but also make the case that Python tools and Python programmers are likely to actually take advantage of it.

On Mon, Feb 3, 2020 at 3:58 AM Richard Damon <Richard@damon-family.org> wrote:
What you're actually asking for is a way for a refactoring tool to recognize that the string "bar" is a reference to the bar in foo.bar. You're NOT asking for the Python compiler to recognize that. There are lots of ways to do this. And Ricky Teachey's examples show that this is pretty ugly. On Mon, Feb 3, 2020 at 9:38 AM Ricky Teachey <ricky@teachey.org> wrote:
f"The field {nameof(foo)}.{nameof(foo.bar)} can be refactored." Here's my alternative: f"""The field {"foo.bar"} can be refactored.""" Since there's no real reason that you'd use {} around a literal string, we have our refactoring tool recognize that syntax as a variable reference. It has no net effect on the running code. If we don't want foo to be refactored, we write instead: f"""The field foo.{"bar"} can be refactored.""" And if we just want the string to reference "bar" but want to make sure it's foo.bar not something_else.bar, we could write this: f"""The field {"foo" and "bar"} can be refactored.""" --- Bruce

On 2020-02-04 3:33 a.m., Bruce Leban wrote:
Huh I didn't think of using string literals in fstrings like that. (altho, are "raw" fstrings a thing?) Anyway, I like how we've all been focusing on refactoring but how about this use-case instead: let's say one has a function that takes an object and an attribute name because Reasons: def create_attr(obj, attr): setattr(obj, attr, Thing(attr)) def screw_attr(obj, attr): getattr(obj, attr)._reset() delattr(obj, attr) class Foo: def __init__(self): create_attr(self, nameof self.__mangled) def bar(self): screw_attr(self, nameof self.__mangled) there's currently no way to get a string representation of a mangled attr and a nameof operator would let you do so.

A statement like print("bar", foo.bar) would be very hard to notice that
the "bar" match the foo.bar, while
print(nameof(foo.bar), foo.bar) makes the connection explicit.
Isn’t someone working on a “debug string” PEP that would mitigate this? Maybe not a full PEP: https://bugs.python.org/issue36774 And https://bugs.python.org/issue36817 I can’t quit tell where that is at — but it seems it may well address this problem. -CHB -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Tue, Jan 21, 2020 at 1:49 PM Johan Vergeer <johanvergeer@gmail.com> wrote:
We can get the name of the class with "type(ins).__name__". If you want to get the names right it would be easier to loop over a list of strings and use 'getattr' on them, which would mean you only have to change the name in one place rather than two.

Isn't the name of the class more reliably `type(ins).__qualname__`? At any rate, I've actually wished for a shortcut to the name of an object's class- of the name of the class object itself- many times in the past. Mostly when writing reprs and exception messages. Not sure if that is in line with OP's suggestions. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Tue, Jan 21, 2020 at 2:03 PM Todd <toddrjen@gmail.com> wrote:

On Tue, Jan 21, 2020 at 02:25:56PM -0500, Ricky Teachey wrote:
Isn't the name of the class more reliably `type(ins).__qualname__`?
Depends on whether you want the plain old name of the class, or the qualified name of the class.
At any rate, I've actually wished for a shortcut to the name of an object's class- of the name of the class object itself- many times in the past.
Write a one-line helper function that returns type(obj).__name__ or __qualname__, whichever you prefer.
Mostly when writing reprs and exception messages. Not sure if that is in line with OP's suggestions.
No. As far as I can tell, Johan wants to capture the name of a name binding, not the name of a class. For example, given: x = 1 then you want nameof(x) to return 'int' (the name of the class) and Johan wants it to return 'x' (the name of the variable). But what should these things do? x = y = z = 1 nameof(1) nameof(z) nameof("Gumby") nameof(mysequence[0]) It isn't clear what precisely counts as the name of a variable. Johan's nameof operator looks like a function. But it can't be a function, for obvious reasons. Or at least, they're obvious to me, I don't know if Johan understands why a regular function can't easily/efficiently/unambiguously return the name of an object. Johan, it would be nice when making a proposal if you spelled out precisely what you expect it to do, as well what you don't expect it to do, especially if we don't know you well enough to predict if you are an expert or a novice. Otherwise we risk either talking down to you, or talking over your head. So for obvious reasons, nameof() cannot be a regular callable object. It has to be some sort of magic behind it so that if we write this: x = y = None nameof(x) nameof(y) the first call returns "x" and the second call returns "y", even though both objects are identically None. Fortunately we can already do this from Python today, using special variable quoting syntax. Instead of writing `nameof(x)`, just replace the function call with quote marks, and at compile time Python will compile in the name of the variable 'x' as if by magic. And best of all, quoting a variable name in this way is only two keypresses instead of ten. (It also works with double quotes too.) /deadpan Okay, I'm kidding, but only a little bit. Nevertheless, `nameof` is not an ordinary function, and it shouldn't look like an ordinary function. I don't buy Johan's argument: "This makes sure the developer cannot forget to update the name of a member." Of all the millions of places one might use an attribute, and forget to update it in the source code, only a tiny proportion will be guarded by a call to nameof. And even then, there will be cases -- quite common cases -- where one might forget to update the name inside the nameof() call, and not get an exception. For instance, I've frequently refactored names where I've ended up swapping two names. I can't think of an example off the top of my head right now, and I don't feel like trawling through years of history to find one, so I'll make one up: the variable "spam" is renamed to "eggs" and the "eggs" variable is renamed to "spam" Now if you refer to both: header = f"1:{nameof(spam)} 2:{nameof(eggs)}" # and some lines of code later on... line = f"1:{spam} 2:{eggs}" it's easy to swap the names in one place but not the other. I've done this more times than I care to admit to, and nameof() wouldn't have saved me. The bottom line is this: this has only a narrow use-case ("I need to print the name of a variable or attribute") and even in those use-cases, you still have to update the variable name in two places regardless of whether you write: # needs to be refactored to "eggs", eggs "spam", spam or # needs to be refactored to nameof(eggs), eggs nameof(spam), spam The second version may have the advantage that it will fail with an exception, instead of silently outputting the wrong string. But only sometimes. Which brings me back to my half tongue-in-cheek response about quoting variables with quote marks... as I see it, the easiest way to get this "nameof" operator to work is a source code transformation. The interpreter could simply do a compile-time replacement: nameof(spam) -> "spam" nameof(self.eggs) -> "eggs" nameof(None) -> "None" nameof(123) -> "123" or whatever semantics we desire. Seems like a lot of effort in adding this to the language, testing it, documenting it, dealing with the invariable problems when somebody uses "nameof" as a regular variable or function, etc etc etc, when we can just tell people: If you want the variable name as a string, use a string. And pay attention to what you are doing when you rename things. -- Steven

On 22/01/2020 12:03, Anders Hovmöller wrote:
He was pretty clear in saying he wanted the same thing as in C#. That no one in this thread seems to have looked that up is really not his fault in my opinion.
Oh, plenty of people have looked it up. The problem is that it relies on part of the nature of C# (variables are lvalues) that simply isn't true in Python, which I don't think the OP realised. -- Rhodri James *-* Kynesim Ltd

On 1/22/20 7:08 AM, Rhodri James wrote:
Or to expand on that, in C# and related languages, variable names actually HOLD some value (which might be a special type of value called a pointer), and a given object will either be in a specific variable name, or off somewhere in the heap with no name. We might have a variable with a pointer value to another object, and there it can be useful to query the object through that pointer and ask what is the name of the variable you are in, as we might not know it at the site of usage. In Python, variables don't hold values, but refer to them. A given value can easily be referred to by many names equally, and there is no such thing as a pointer (which gets you to a name) only multiple references to the same object. Thus nameof(x) can ONLY be "x" in Python (or an error is x isn't something that is a name), as at best x is referring to some object, but that object doesn't have a special name to refer to it that is its holder. Yes, one example where that linkage might be useful is it documents in the code that the string value is actually supposed to be the name of the variable, so a refactoring that changes the variable should change the string too, such a semantic link between a variable and its spelling is ill advised, and would only be used in a debugging environment with something like print("x", x) or some similar purpose function, and in that context, such prints should not normally be long lived or are part of long term logging in which case the stability of the label might actually be preferred to not break parsers for the log output. -- Richard Damon

Does it? How? https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/... seems pretty clear to me that it's a rather simple extraction of an AST node, lvalue or not doesn't seem relevant at all. Can you point me to something where this isn't the case? / Anders

On 1/22/20 8:05 AM, Anders Hovmöller wrote:
The part from the C# docs that people perhaps overlooked is that nameof is a compile-time function. It has access to the variable's name not just its value. Definitely, a runtime-function in Python has enormous challenges in trying to replicate this behavior. Not that I'm advocating adding something like this... --Ned.

On Wed, Jan 22, 2020 at 5:48 AM Johan Vergeer <johanvergeer@gmail.com> wrote:
Some objects (including types) have "inherent names", which can be accessed using the __name__ attribute: def __repr__(self): return f"{type(self).__name__}(... etc ...)" I'm not sure how this compares to what nameof(Person) should return, but the above idiom (or something like it) is very common in Python, as it allows repr to acknowledge a subclass. If you create "class Martian(Person): pass", then a Martian's repr will say "Martian". On the other hand, if you actually want "the name of the surrounding class", then that can be spelled __class__.__name__, and that will always be Person even if it's been subclassed. Not nearly as common, but available if you need it. For the attributes, though, there's no inherent name (at least, I presume self.name is a string and self.age is some sort of number). You CAN do some neat tricks with f-strings: return f"{self.name=}" but that would include "self.name" rather than simply "name", which I think is what you want. I would suggest creating a helper function that takes a list of attribute names, loops over them, and grabs the attributes. Using getattr in a loop is going to be less error-prone than your proposed form, which still has to have the word "age" repeated twice. Hmm. Maybe this should be a recipe in the docs, or something: "how to make a repr that reconstructs an object". def describe(obj, attrs): attrs = [f"{a}={getattr(obj, a)!r}" for a in attrs] return f"{type(obj).__name__}({", ".join(attrs)})" def __repr__(self): return describe(self, "name age spam ham location".split()) This comes up often enough that I think it'd be a useful thing to point people to. ChrisA

On 01/21/2020 11:25 AM, Chris Angelico wrote:
I'm not sure what you mean, but: --> class Person: ... def __init__(self, name): ... self.name = name ... def __repr__(self): ... return '%s(name=%r)' % (self.__class__.__name__, self.name) ... --> class Martian(Person): ... pass ... --> p = Person('Ethan') --> m = Martian('Allen') --> p Person(name='Ethan') --> m Martian(name='Allen') (Same results with f-strings. Whew!) -- ~Ethan~

On Wed, Jan 22, 2020 at 9:04 AM Ethan Furman <ethan@stoneleaf.us> wrote:
Yes, that's exactly what I mean, and exactly why self.__class__ is used here. If you actually want "Person" even if it's actually a Martian, you can use __class__.__name__ rather than self.__class__.__name__ to get that. ChrisA

On 1/21/20 1:42 PM, Johan Vergeer wrote:
def __repr__(self): return f"{nameof(Person)}({nameof(self.name)}: {self.name}, {nameof(self.age)}: {self.age})"
I'm trying to understand what you are looking for. Why isn't the above line just: return f"Person(name: {self.name}, age: {self.age})" That is, instead of "{nameof(self.name)}" just use "name"? You had to type "name" in your string anyway. How would nameof be helping here? --Ned.

I believe Python 3.8's '=' f-string specifier ( https://docs.python.org/3/whatsnew/3.8.html#f-strings-support-for-self-docum...) combined with __name__ does what you'd want: return f'{self.__class__.__name__}({self.name=}, {self.age=})' Outside of the __name__ dance, this is a bit more concise (and IMO readable) than C#'s nameof. On that note, for simple classes like this, namedtuples or 3.7's dataclasses would serve the purpose a bit more nicely. On Tue, Jan 21, 2020, 12:51 PM Johan Vergeer <johanvergeer@gmail.com> wrote:

Why? That looks like more code to accomplish exactly the same thing. On Tue, Jan 21, 2020 at 1:49 PM Johan Vergeer <johanvergeer@gmail.com> wrote:
-- CALVIN SPEALMAN SENIOR QUALITY ENGINEER cspealma@redhat.com M: +1.336.210.5107 [image: https://red.ht/sig] <https://red.ht/sig> TRIED. TESTED. TRUSTED. <https://redhat.com/trusted>

On Jan 21, 2020, at 10:48, Johan Vergeer <johanvergeer@gmail.com> wrote:
What would the semantics of nameof be in Python? Would it just be lambda obj: obj.__name__? Or some fancy inspect-module style chain of “try this, then that, then the other”? Or does it need to look at the compiled source code context or something? Unless it’s the last one, can’t this just be a normal function rather than a special operator? And if so, why does it need to be in the stdlib, much less a builtin, rather than just a function you stick in your toolkit or install off PyPI? I have two functions that I use that are basically obj.__name__ and type(obj).__name__ that I just import or copy-paste whenever I’m writing a lot of classes that need a repr, which seems to be exactly your use case, and I’ve never been bothered by doing that, much less considered that maybe it’s worth having either one as a builtin, before now.

On Jan 21, 2020, at 13:32, Andrew Barnert <abarnert@yahoo.com> wrote:
Sorry; I didn’t notice the nameof(self.age) part there. That definitely does need to look at the source (or something else, like the bytecode), because whatever value is in self.age doesn’t know that it’s in self.age (especially since it’s probably in lots of other variables as well); all it knows is that it’s the int object with value 42. But it seems like nameof(self.age) always has to be just “age”, which you already have to type inside the nameof if you want it to be findable, so it’ll never be useful. Anywhere you could write `{nameof(self.age)}` you could just more simply write `age`. The big difference in C# is that variables are lvalues. In Python, self.age is just a reference to that int object 42 somewhere; in C#, this.age is a reference to the int-sized, int-typed location 8 bytes after the start of “this” (which can decay to the int value stored there on demand), and the runtime can use that to figure out that it’s the “age” attribute of this via reflection (or maybe the compiler can do that). This also means you can pass around a reference to this.age and mutate this through that reference (and presumably nameof works on that reference too), which doesn’t make any sense in Python.

On 21 Jan 2020, at 22:50, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
But it seems like nameof(self.age) always has to be just “age”, which you already have to type inside the nameof if you want it to be findable, so it’ll never be useful. Anywhere you could write `{nameof(self.age)}` you could just more simply write `age`.
That misses the point. Refactoring tools for example won't know how to handle the rename of the variable foo in this example: foo = 1 n = 'foo' print(n, foo) If you had n = nameof(foo) It would know what to do. That's why this feature exists in C# and AFAIK also in Swift for example. / Anders

On 1/21/2020 4:32 PM, Andrew Barnert via Python-ideas wrote:
What would the semantics of nameof be in Python? Would it just be lambda obj: obj.__name__? Or some fancy inspect-module style chain of “try this, then that, then the other”? Or does it need to look at the compiled source code context or something?
I think some wrapper around inspect.getmembers() would be the easiest/best thing to do. dict(inspect.getmembers(obj))['__name__'] With some error checking for the KeyError if inspect.getmembers can't get a name for the object you passed in. There are probably more performant ways to write this, but this was my easy one-liner version. Eric

On 1/21/2020 4:50 PM, Eric V. Smith wrote:
And in case it's not clear, my point is: Many things in Python don't have have names. For those that do, the inspect module knows about them, so use it. And if there's something that has a name that inspect currently doesn't recognize, then if we fix inspect to understand the name of that object, everyone who uses inspect would win. Eric

On Tue, Jan 21, 2020, at 16:32, Andrew Barnert via Python-ideas wrote:
The C# version becomes a string constant and doesn't have to look at anything other than the expression itself. It is the literal name of the variable [or attribute] in the expression, irrespective of its value. The intent is for it to be a string literal that survives refactors, so you could do nameof(a_person.age) and that would compile down to "age" [without actually performing an attribute access. C# allows you to do this with instance members without making an instance, but it is unclear what the best way to do this in python would be], but if you used a refactoring tool to rename the age attribute, it would change this expression along with all of the other places it is used, to give it the new attribute name. There's no fancy run-time lvalue reflection stuff going on as you suggested in your other post, it is just the name from the expression, as a string constant. It is purely a compile time operation (which is why it has to be an operator, not a function)

Thanks everyone for your responses. I would like to take all the information you gave me and do some research on it. I'll try to get it done this weekend or beginning of next week.

It is a couple of days later, but I managed to create a more expanded proposal. This proposal is about having a simple and consistent way of getting the name of an object. Whether it is a class, type, function, method or variable or any other object. # Why? ## Usage in strings The first situation this could be used is in strings (for example in `__repr__`, `__str__` and `print()`) I've come across too many situations where the developer made a typo (which is usually the developer is a hurry or just having a bad day) or in the case of a refactoring where the developer didn't rename the object in the string representation. To be honest, I am a big fan of IDEs, like PyCharm, which have great refactoring tools, but it doesn't refactor strings. ## Usage in comparisons Another situation is when you want to do a comparison. An example of this would be: ```python def my_factory(class_name: str): if class_name == "Foo": return Foo() if class_name == "Bar": return Bar() ``` I know this is a very simple example that can be solved with the example below, but it would be nice if we can do the same with methods, functions and attributes. ```python def my_factory(class_name: str): if class_name == Foo.__name__: return Foo() if class_name == Bar.__name__: return Bar() ``` ## The Zen of Python The Zen of Python has a couple of items that apply to this one in my opinion: Beautiful is better than ugly. Simple is better than complex. Sparse is better than dense. Readability counts. **There should be one-- and preferably only one --obvious way to do it.** Although that way may not be obvious at first unless you're Dutch. # How? From the messages in this thread I concluded there is some confusion about what I would like to achieve with this proposal. In this part I will try to make it more clear what the behavior would be. For now I'll stick to the C# naming `nameof()`. ## Class names When you want to get the name of a class, you should just use the name. So `nameof(Foo)` becomes `"Foo"` and `nameof(type(foo))` also becomes `"Foo"`. The results are basically the same as `Foo.__name__` and `type(foo).__name__`. ## Function names When you want to get the name of a function, you would do the same you do with a class. ```python def foo(): ... nameof(foo) #Returns 'foo' ``` This is (again) the same as `foo.__name__` ## Attribute names You should be able to get the name of an attribute. ```python class Foo: bar: str = "Hello" def __init__(self): self.baz = "World" def __str__(self): return f"{nameof(self.bar)}: {bar}, {nameof(self.baz): {baz}}" # Returns "bar: Hello, baz: World" foo = Foo() nameof(foo) # Returns "foo" nameof(foo.bar) # Returns "bar" ``` As Chris Angelico suggested we can already use a special syntax for f-strings which is pretty cool, but it has the limitation that we have less control over the output. ```python return f"{self.name=}" # returns `self.name="something"` ``` ## Invalid usage There are also situations that will return an error. ```python nameof(1) nameof("foo") nameof(["bar", "baz"]) ``` ## Stuff to think about There are also situations that I haven't been able to make a decision about and I think these should be discussed further down the road. ```python nameof(None) nameof(type) nameof(int) _foo = Foo() nameof(_foo) #Should this return "_foo" or "foo"? ... ``` ## How should the interpreter handle it? I think the interpreter should handle it as anything else that is passed to a function, so when the value passed to the `nameof()` function doesn't exist, an error should be thrown. # How can this be built in the Python language (or a library) Some people responded this will be very hard to implement because of the way Python is built. To be honest, I don't know nearly enough about the internals of Python to make a solid statement on that. I also don't know how the new f-string syntax `f"{self.name=}"` works under the hood, but it does give me the impression that implementing this proposal should be possible. # What about `__name__`? Most of the examples I wrote above can be solved by just using `__name__`, which solves most use cases, except for variable and attribute names, which cannot be resolved right now because objects don't have names. So when we want to follow `There should be one-- and preferably only one --obvious way to do it.` it would be better to use `__name__` on an object, but I believe that would cause breaking changes. What I mean is: ```python class Foo: ... foo = Foo print(foo.__name__) # Prints "foo" foo = Foo() print(foo.__name__) # Throws AttributeError: 'Foo' object has no attribute '__name__' ```

On Jan 30, 2020, at 11:20, Johan Vergeer <johanvergeer@gmail.com> wrote:
I think this is glossing over something very important. You really aren’t trying to get the name of an object at all, you’re trying to get the name of a _variable_. After you write foo.bar = 2, the object in foo.bar is just the number 2, an object of type int that’s probably the same object that’s referenced in dozens of other places, both named and anonymous, in your program’s current state. It can’t possibly have the name “bar”. What _can_ have the name “bar” is the variable that references that value. But that variable isn’t a thing that exists in Python at runtime. A compile-time transformation could convert nameof(foo.bar) into “bar”. In fact, the compiler already pretty much has to do exactly that to emit the code for foo.bar, which is effectively 'push the object in too, then push the string “bar”, then do an attr lookup with those two things'. So nameof cannot be a function. It has to be a special compiler-time operator. The code emitted for nameof(foo.bar) has to be effectively the same code emitted for the literal “foo”. And this affects a whole lot of your other points below:
The way you already do this today is usually to look up the class name in a dict—either directly, or as part of a namespace lookup (e.g., getattr(self, class_name)). Having nameof wouldn’t really help here. However, it could help on the _caller_ side: you could call my_factory(nameof(Foo)). In this trivial case, there’s no reason for that, because if you have the name Foo you already have the class object Foo and don’t need a factory in the first place. But there might be less trivial cases where it might be useful.
I know this is a very simple example that can be solved with the example below, but it would be nice if we can do the same with methods, functions and attributes.
But you can already write that factory that way. Methods are attributes, and both can be looked up with getattr. Functions are attributes of the module object, and members of globals, so they can be looked up either way. You don’t need nameof for this kind of dynamic lookup, and it doesn’t help to add it. You only need nameof got static (compile-time) lookup, to serve the purposes from your initial paragraph, like making sure the name gets caught by refactoring tools (which can be sure that nameof(Foo) must rename along with Foo, but can’t know whether the string literal “Foo” needs to change).
So what happens here: class Foo: pass Bar = Foo print(nameof(Bar)) If you compile nameof(Bar) into a call to a normal (runtime) nameof function that returns param.__name__, you’re going to print out Foo. If you compile it to just Bar.__name__, you’re still going to print out Foo. If you compile it to the string "Bar", you’re going to print out Bar. And I think that’s what you actually want here. Meanwhile, I don’t see how nameof(type(foo)) can work. At compile time, we have no idea what the type of foo is. Consider this case: foo = Foo() if spam else Bar() Even if the compiler were smart enough to know that Foo and Bar are guaranteed to be names for the same object (which they actually might not be even after Bar = Foo—you can write a globals dict whose __setitem__ does something crazy… but ignore that), it still can’t know which name we used here without knowing the runtime value of spam, which it can’t possibly have. As a side note, this implies that making nameof look like a function call (with parentheses around an argument) is misleading. Everything that looks like a function call in Python is actually compiled as a function call, and I don’t think you want to break that. And there’s no real reason to—Python already has spelled-out prefix operators like not, so why shouldn’t nameof be the same? (In C# things are different.)
If you compile nameof(foo.bar) to a function call, that function gets called with the string "Hello". There’s no way you can get anything else out of that string at runtime. (You can use horrible frame hacks to inspect the caller’s context and try to guess what it was trying to pass you, which will work in many cases, but if you’re proposing a new language feature why make it depend on that?) What you want to compile this to is pretty clearly just the string “bar”. Which is immediately available at compile time. You do need to go through the whole grammar to decide exactly what productions you should be able to use in a nameof and what the result should be. But that shouldn’t be too hard. (And it’s a necessary first step toward an implementation anyway.)
Why should these be any different from anything else? For type and int, these are just names like any other (except for usually being found in builtins rather than the module’s globals), and the things they name are types like any other. (They’ve even got a __name__ like other type values.) None is a bit special because it’s sort of a keyword to prevent people from accidentally rebinding the name to a different value, but other than that it’s still basically just a builtin name, and the thing it names is a value no different from “hello” or 2 in your other examples.
_foo = Foo() nameof(_foo) #Should this return "_foo" or "foo"?
How could it possibly return “foo”? Unless you’re suggesting that the occasionally-followed convention of naming a generic instance of a type with the lowercase version of the type’s name should be enshrined in the language?
## How should the interpreter handle it?
I think the interpreter should handle it as anything else that is passed to a function,
But it can’t be.
so when the value passed to the `nameof()` function doesn't exist, an error should be thrown.
But you can’t know that at compile time. This is actually the biggest problem. In C#, the compiler has to know the names of every variable, attribute, etc. In Python, it can’t. There’s nothing stopping me from doing this: if spam: foo = Foo() … and now the variable foo may or may not exist. Or I can even do this: globals()[name] = 3 … and if name happens to be holding the string “foo” then foo will exist. There is a special case here related to local variables, but if you want this to work for globals and attributes (which I assume you do, because all of your examples are globals or attributes) that isn’t relevant.
You don’t need to know the internals, at least if you can convince someone who _does_ know the internals to do the work for you. But you do need to know the basics of what variables are in Python as opposed to C#.
That’s not right. Classes and functions are objects, and they have names. But the real issue is that you don’t _want_ the name of the object, you want the name of the variable. And no object knows the name of the variable you used to access it. Even for classes and functions, the fact that class statements and def statements happen to produce a variable with the same name that’s stored in the object doesn’t mean you want the name stored in the object, because it’s trivial to create a different name for the same object (assignment, argument passing, import as, …), and when you do, it’s that different name that you want.

On 2020-01-30 7:17 p.m., Andrew Barnert via Python-ideas wrote:
Consider: x=nameof(foo.bar) in today's python becomes: foo.bar x="bar" and when running this you get an AttributeError or something. the benefit is that "bar" is only typed once, and the attribute access (and thus error-raising code) is tied to the resulting string. either you change both the attribute access *and* the resulting string, or you get an error. (correct me if I'm wrong.)

On Jan 31, 2020, at 11:01 AM, Soni L. <fakedme+py@gmail.com> wrote:
One issue I am seeing is that x = nameof(foo.bar) is crossing the line between compile time and run time behaviors. The resultant string, “bar” needs to be generated at compile time, but the operation still needs to do a check at run-time to determine if that IS the right result, as if foo doesn’t have a bar attribute it needs to raise an error instead.

On 1/02/20 6:15 am, Richard Damon wrote:
I don't think I would bother with the runtime check. This is mostly going to be used in a context where you're writing out the same thing again to get its value, e.g. print("The value of", nameof(foo.bar), "is", foo.bar) This can be translated to print("The value of", "bar", "is", foo.bar) and you'll still get an AttributeError if foo doesn't have a bar attribute. -- Greg

On Jan 31, 2020, at 08:03, Soni L. <fakedme+py@gmail.com> wrote:
That does work, but that means foo.bar has to exist and have a value before you look up the name. Consider these cases: class Spam: def __init__(self): self.eggs = 42 print(nameof Spam.eggs) # AttributeError class Foo: pass foo0 = Foo() setattr(foo0, nameof foo0.bar, 42) # AttributeError foo1 = Foo() print(nameof foo1.bar) # AttributeError foo1.bar = 42 foo2 = Foo() if spam: foo2.bar = 42 print(nameof foo2.bar) # AttributeError if not spam foo3 = Foo() Foo.bar = 23 print(nameof foo3.bar) # works fine baz = MyRPCProxy(baseuri, endpoint) print(nameof baz.bar) # makes a remote procedure call on the server and ignores the result or raises AttributeError depending on the server These all seem more confusing than helpful—and very different from C#. If you explain that nameof is a mix of compile time and run time, or just explain that it compile to the same thing as the code as you gave, people could figure it out, but it still seems both weird and undesirable. Python variables just don’t have a static type, and even if they did, the attributes are dynamic rather than determined by the type anyway. And that isn’t some edge case that occasionally comes up; that Spam example is the usual ordinary way for a class to give its instances attributes.) However, that does raise the possibility that maybe mypy (or your IDE or favorite other static type checker tool) should be doing the check, because Python variables often do have a static type and it often does declare the variables and “often” may not be good enough for language semantics but it’s exactly the point of optional gradual type checking. So: @dataclass class Spam: eggs: int = 42 spam.cheese # If your typing-aware IDE will flag this nameof spam.cheese # … it will do exactly the same here Now, when you’re using mypy/etc , nameof is just like C#, and gives you exactly the desired benefits, but all the Python compiler has to do is emit “cheese”. And when you aren’t using mypy? Then it just doesn’t get checked. Same as all other static typing errors. What happens if spam: Any, or if spam: Spam but Spam didn’t statically deflate its attributes? At first glance, given the way optional gradual typing generally works, this shouldn’t be an error. But if we think of nameof as a compile time operator that’s meant to act like C#, maybe it is a static typing error to use it on an attribute that can’t be statically checked? Or maybe a warning? I don’t know. Maybe that should even be left up to the type checkers as a QoI issue rather than defined by Python?

On 2020-01-31 2:36 p.m., Andrew Barnert wrote:
All of these seem to be working exactly as I'd expect nameof to work. In fact these are exactly how I'd prefer it to work, personally. I'm not OP tho.
baz = MyRPCProxy(baseuri, endpoint) print(nameof baz.bar) # makes a remote procedure call on the server and ignores the result or raises AttributeError depending on the server
Yes. I know.
But here's the thing -- C# is statically checked. Python is dynamically checked. (and yes, Python *does* have type checking, among other things.) I figured this would be the correct way to adapt a statically checked syntactic construct into an *equivalent* dynamically checked syntactic construct. The static construct has: - Errors at compile-time if stuff gets incorrectly refactored The dynamic construct has: - Errors at runtime if stuff gets incorrectly refactored And this goes for anything you can contrast between static and dynamic constructs: classes, methods, everything. They always take a compile-time error and turn it into a runtime error. I strongly feel like it should be the same here.

On Jan 31, 2020, at 14:51, Soni L. <fakedme+py@gmail.com> wrote:
All of these seem to be working exactly as I'd expect nameof to work. In fact these are exactly how I'd prefer it to work, personally. I'm not OP tho.
Really? These seem like exactly the kinds of places I’d want to use nameof (so the IDE can magically refactor for me), and I can’t do that if it raises exceptions at runtime instead of working. It only seems like the right thing for the trivial case that, as Greg Ewing says, would already work fine without a check anyway.
Not so much. You _can_ do dynamic type checking in Python, but 80% of the time you don’t, you just accept anything that quacks as the right type. In C#, if you pass a complex or a string to a function that wanted an int, you get a compile-time type error. Python doesn’t have any equivalent runtime error, unless you manually write code to check isinstance and raise. And even that can’t handle all types that really exist in Python—there is no way to tell if something is an Iterator[int] for example. Of course if the function tries to return param+1, that will raise a TypeError if you passed a string—but not if you passed a complex. And attributes are if anything even more “ducky” than function signatures. While you _can_ restrict the set of attributes for instances of a type with a custom __setattr__ or with __slots__ or whatever, usually you don’t; most classes’ instances can have whatever attributes they want.
I figured this would be the correct way to adapt a statically checked syntactic construct into an *equivalent* dynamically checked syntactic construct.
But it’s not equivalent. In all those examples I gave, you statically know whether foo.bar exists, and therefore the compiler can check that nameof is correct, but you dynamically don’t know, so the runtime cannot check that nameof is correct. It could check something significantly different, and less useful, but it can’t check the equivalent thing, because there _is_ no equivalent thing to “Foo instances have an attribute named bar” in Python, even at runtime.

On 2020-02-01 12:00 a.m., Andrew Barnert wrote:
Yes, really. It's dynamic, so it must pay attention to the context it's being used in.
Okay here's one of the examples you gave: class Spam: def __init__(self): self.eggs = 42 print(nameof Spam.eggs) # AttributeError I don't know how C# does it, exactly, *but I'd expect this to be an error!* C#, Java, etc have the concept of static vs instance variables. I'd expect referring to an instance variable from a static context (such as this nameof Spam.eggs) would result in an error. Additionally those languages have null, so you could do something along the lines of: Spam dummy = null; nameof dummy.eggs if you really wanted to. But arguably you shouldn't, because you're doing it in the wrong context (class vs instance). IDEs are very much capable of refactoring strings. On the other hand, runtime errors would benefit those of us who use e.g. plain vim and no IDE. I don't use an IDE. thankfully the general case is that you get runtime errors where you forget to refactor something. but sometimes, you don't. and that's where this would fit in IMO. so I'm gonna say this proposal is completely, 100% useless for IDE users. if your IDE doesn't do quite what you want, you should add an extra plugin or two to make it do so. but this feature would be a huge win for ppl who don't use IDEs. like myself.

On Jan 31, 2020, at 19:30, Soni L. <fakedme+py@gmail.com> wrote:
Why? The name of a variable does not depend on its runtime context. Which is a good thing, because by the time you get to that runtime context you don’t even _have_ a variable; there is no such thing as variables in the Python data model.
I don’t think it is. I don’t have a C# compiler handy, but from the spec (sadly the “examples” section is just “TODO”…):
The meaning of the named_entity of a nameof_expression is the meaning of it as an expression; that is, either as a simple_name, a base_access or a member_access. However, where the lookup described in Simple names and Member access results in an error because an instance member was found in a static context, a nameof_expression produces no such error.
…
A nameof_expression is a constant expression of type string, and has no effect at runtime. Specifically, its named_entity is not evaluated, and is ignored for the purposes of definite assignment analysis (General rules for simple expressions). Its value is the last identifier of the named_entity before the optional final type_argument_list, transformed
So an instance member in a static context is not an error, and the value is the name of the member, unless I’m reading something wrong. Also, this is the same way operators like sizeof, type of, and offsetof work in C#, C++, and C, isn’t it?
How is that relevant? Clearly the result should be the string “eggs” in C#, right? And in my static-only version of the proposal, the same would be true in Python, but in your version it would be an error. And a refactoring tool should rename this eggs when the member is named, which is the whole point of the proposal. So why is doing something different from C# that breaks the point of the feature better?
IDEs are very much capable of refactoring strings.
No they’re not. They have to guess at it using heuristics, which are complicated, and often get it wrong. Because it’s inherently ambiguous whether the string or substring “spam” is meant as the name of an attribute or as normal English text.
On the other hand, runtime errors would benefit those of us who use e.g. plain vim and no IDE.
I mostly use emacs rather than an IDE. But I can still use refactoring tools. There’s nothing about a refactoring tool that demands that it be built into an IDE just because it could be—in the same way that PyCharm integrating a static type checker doesn’t stop me from using mypy.

On Thu, Jan 30, 2020 at 07:17:34PM -0000, Johan Vergeer wrote:
Variables are not objects, and in Python, there are two distinct meanings for "name": (1) "Names" in the sense of name bindings like `spam = expression`. In this sense, objects can have zero, one or more names: # this string has (at least) three names spam = eggs = cheese = "Hello world!" but the *name* "spam" is not an object or a first-class value at all. (2) Some objects, like modules, classes, functions and methods, have a special dunder `__name__` attribute. When people talk about the name of a module, class, function or method, that's what they expect, and that's what they see in the object repr. Most objects have no such concept of a name in sense (2), and most objects are not bound to a name in sense (1). Objects which have both may not agree: def spam(): pass eggs = spam del spam What is the name of the function object bound to the "eggs" name? Should it be "eggs" or "spam"? [...]
To be honest, I am a big fan of IDEs, like PyCharm, which have great refactoring tools, but it doesn't refactor strings.
You should report that to the IDEs as a feature request.
If I saw that code in production, I would strongly suspect that the author isn't very experienced with Python or is trying to write Java (or equivalent) code in Python. There are exceptions, of course, such as if you are getting the class name from user data at runtime. But normally that would be better written as: def my_factory(cls: type): return cls() (This is a toy. In real code, the my_factory() function better do something useful to justify its existence.)
In your earlier example, your sense of "name" is that of name bindings. In this example, your sense of "name" is the object's internal name. These are two different, distinct and independent concepts.
Spoken like somebody who is not used to languages where classes are first-class values. for obj in (Foo, Bar, Baz): print(nameof(obj)) Should that print "obj", "obj", "obj" or "Foo", "Bar", "Baz"? Trick question! Actually I did this earlier: Foo, Bar, Baz = Spam, Eggs, Cheese so perhaps it should print "Spam", "Eggs", "Cheese" instead. How does the nameof() function know which answer I want? The same applies to functions, modules and methods. -- Steven

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.

Sorry, sent early… ignore that and try this version.
On Jan 31, 2020, at 19:58, Andrew Barnert <abarnert@yahoo.com> wrote:
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 A second use is static type checkers. If a type checker sees `nameof spam.eggs`, it can apply whatever rules it would use for `spam.eggs` itself. For example, if it can figure out the type or `spam`, and that type declared its attributes, and there is no attribute named `eggs`, this can be a static type error. 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 automated tools. Compatibility: Because `nameof` is a valid identifier today, there may be code that uses it as a variable name. This means the usual 3-version __future__ schedule is probably needed. And a search through public code to make sure it isn’t a lot more common than you’d expect. Alternatives: Why no parentheses? Because in Python, only function calls take parentheses. In C# (where this feature originated) there are other compile-time operators like sizeof that take parens, and ultimately this goes back to making those operators look like calls to preprocessor macros in 1970s C; that isn’t relevant in Python, so requiring parens would just be confusing for no benefit. Why no runtime behavior? Because there’s nothing that could reasonably be checked. Unlike C#, Python doesn’t have “variables” at runtime; it just has names bound to objects in namespaces. Given an object, there is no way to know what name you used to access it. Also, Python attributes are completely dynamic—in C#, `spam.eggs` means something like “the int-typed value found between 4 and 8 bytes after the start of `spam` in memory”; in Python, it means “the result of calling getattr(spam, 'eggs'), which could be any arbitrary code”. Even if it were possible, it’s not clear what the benefit would be, and without someone making a case for a benefit, it’s not worth trying to come up with something clever in the first place.

Thank you so much for this concrete proposal. I could not have described it clearer myself. I'm not sure about leaving out the parentheses. But this is mostly out of preference. Especially since Python also has a `type()` function. I also thought about using `name()` instead of `nameof()` to be more consistent with that. I can also see your point of view though. Out of personal curiosity: Is the way you described the grammar an official notation, and if so, could you give me a link to some documentation?

But that’s the whole point: type is a function, and nameof is something totally different from a function. (Actually, type is a type whose constructor does something different from constructing an object when passed a single param, but never mind that bit.) Making it look like a function call makes sense for a C family language—function calls, macro calls, old-style annotations (like declspec in Microsoft C), and compile-time operators like sizeof all use the same syntax, and nameof is just like sizeof, so why shouldn’t it look the same? Making it look like a function call in Python wouldn’t make sense. In Python, while you can call all kinds of things (functions, types, objects whose types define __call__) with the same syntax, they always have the same semantics: at runtime, call the value on the left with the values of the things inside parens as parameters. Something with radically different semantics (that doesn’t even evaluate the value of the “parameter”) using the same syntax would be confusing.
Out of personal curiosity: Is the way you described the grammar an official notation, and if so, could you give me a link to some documentation
It’s the almost-BNF notation used in the Python docs. See https://docs.python.org/3/reference/introduction.html#notation for details. If you haven’t skimmed the reference docs, they do a pretty good job explaining the semantics that goes with each construction, the underlying data model, etc. in terms that make sense to Python programmers (as opposed to, e.g., the C spec, which is only intended to make sense to people writing C compilers).

On 1/31/20 10:58 PM, Andrew Barnert via Python-ideas wrote:
Thinking about this, I have a question, IS there existing a refactoring program that can do the rest of the job in Python well. I am not sure there can be. Take an example refactoring problem: We have a logging module to save diagnostic information about program operation. The logging class currently has a member log that we want to change to log_file. In a statically type language, this is fairly easy, scan through the source code, find all references to the symbol log, see if they refer to the logging module or something else (which is easily solvable in a statically typed language, as the compiler needs to do this) and if they refer to the logging module, change the reference. The refactoring program just needs about the same smarts as the compiler. We can't easily do this in Python. In general, we come to the sequence foo.log, in order to determine if we want to change this, we need to know what foo will be every time it gets there. To determine this we need to back track to figure every path of execution to here. In fact, the transformation may not be possible (or may require other changes beyond what we want) as there may be a usage that handles many different types, all that happen to have a log member, so to change one class, we need to change them all (this can also happen in C++ templates which also can use duck typing). This lack of local type information makes the refactoring MUCH harder, and as you make the program smart enough to work on handling this, including strings might not be that hard. My guess is that any such refactoring is going to need to ask the programmer about a number of cases of the usage that the program can't determine, and thus can include strings that match too. -- Richard Damon

People keep mentioning refactoring. It's a red herring. No refactoring tool needs a nameof operator added to the language in order to do its job. And certainly an operator that requires running the program in order to use it is not going to be helpful. Refactoring tools analyze the program; they don't run it. And f-strings are another red herring. There is nothing magical about expressions inside f-strings compared to those outside. Ignoring the red herrings, I see no utility in a nameof operator and no way for it to actually do anything useful. --- Bruce

On 2/3/20 12:02 AM, Bruce Leban wrote:
IF Python had a proper refactoring tool (see my other message where I question the ability to do that) then the nameof operator would clearly help keep logging/debug strings in line with the program definitions. A statement like print("bar", foo.bar) would be very hard to notice that the "bar" match the foo.bar, while print(nameof(foo.bar), foo.bar) makes the connection explicit. This is where such an operation could help with refactoring, having an actual Python attribute reference that the refactoring operation could see, so it knows that the string is based on that attribute and not something else. As I mentioned elsewhere, the issue is that in Python, if we change the attribute bar in class Foo, then we have the problem that we often can't tell if in foo.bar if foo is of type Foo, so we should apply the change. This isn't a problem is statically typed languages, as there we can determine the type of foo, and see if the change applies (at least in most cases). -- Richard Damon

To restate the motivation: the hope is that there is a potentially large benefit of being able to more easily refactor code with something like a nameof(). I am going to make the claim that: 1. this benefit is actually minimal and does not address a lot of other existing refactoring problems/chores, and 2. comes at the cost of a possible loss of readability, and therefore isn't worth the trade Consider the following typical code (I hope it is nice; I feel like I can certainly read it): import logging import functools class FunctionLogger: """Records use of a function. The optional `log` parameter is to be a callable that accepts a string. It is logging.info by default. """ log = logging.info def __init__(self, log=None): if log is not None: self.log = log def __call__(self, func): func_name = func.__name__ @functools.wraps(func) def wrapper(*args, **kwargs): try: self.log(f"called {func_name!r}") except: cls_name = type(self).__name__ logging.exception(f"failed to log {func_name!r} call; is {cls_name}.log set correctly?") finally: return func(*args, **kwargs) return wrapper Let's think through: what refactoring must occur to change the "log" parameter to something else? And, how readable does the code remain afterward? At least some of the code could certainly benefit from being more easily refactored (by an IDE) with nameof(), but how much? import logging import functools class FunctionLogger: # NOTE: this docstring will result in a runtime error, so can't even use nameof() here to help ourselves f"""Records use of a function. The optional `{nameof(FunctionLogger.log)}` parameter is to be a callable that accepts a string. It is logging.info by default. """ log = logging.info # no need for nameof() here, but see below * def __init__(self, log=None): # IDE will refactor the init signature SEPARATELY (see below *) if log is not None: # no help from nameof() in __init__ body # IDE will get this one just fine anyway; shouldn't use nameof() in this situation # using it actually hurts readability setattr(self, nameof(self.log), log) def __call__(self, func): func_name = nameof(func) # it's different, but NOT an improvement over func.__name__ @functools.wraps(func) def wrapper(*args, **kwargs): try: self.log(f"called {func_name!r}") except: cls_name = nameof(type(self)) # different, but NOT an improvement over type(self).__name__ log_param_name = nameof(self.log) # ok, HERE is a place we are definitely going to benefit from nameof() # readability of next line might actually be slightly improved...? But perhaps it's also worse...? # but the IDE will refactor next line automatically, which is handy. logging.exception(f"failed to log {func_name!r} call; is {cls_name}.{log_param_name} set correctly?") finally: return func(*args, **kwargs) return wrapper * For the class level member and init signature/body: the IDE won't know to include the class member and the init signature/body in a refactor of a member-level variable, and this problem isn't helped by nameof(). Multiple refactoring chores have to be completed to change the parameter name: 1. the init signature, 2. the class level variable, 3. object level variable, 4. the class docstring, 5. all of the f strings. Using a nameof() only totally prevents one of them (the f strings; it can't help with the docstring). So I guess there is SOME benefit here. But I think it comes at the cost of some potential loss of readability, and there are some major places in which nameof() doesn't bring any help at all (looking at you, class docstring). And there is a ready alternative: use a global if you think you might rename your parameters later (see code at bottom). This rolls TWO of the refactoring chores into one (the f strings and the docstring). *Bottom line: refactoring remains a chore. The win is minimal. Do nothing option is preferred.* import logging import functools _FOO = "foo" # haven't decided on .foo member name yet... class FunctionLogger: # with a global, this docstring will work! f"""Records use of a function. The optional `{_FOO}` parameter is to be a callable that accepts a string. It is logging.info by default. """ log = logging.info def __init__(self, log=None): if log is not None: self.log = log def __call__(self, func): func_name = func.__name__ @functools.wraps(func) def wrapper(*args, **kwargs): try: self.log(f"called {func_name!r}") except: cls_name = type(self).__name__ # employ the global below for the error message, mischief managed logging.exception(f"failed to log {func_name!r} call; is {cls_name}.{_FOO} set correctly?") finally: return func(*args, **kwargs) return wrapper --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler

On Feb 3, 2020, at 03:59, Richard Damon <Richard@damon-family.org> wrote:
This is the same as Smalltalk, ObjC, Ruby, f-script, and all of the other languages that use the same dynamic type/data model as Python. And Smalltalk was the first language to have practical refactoring tools (although I don’t think they were called that until Ralph Johnson’s refactoring object browser in the early 90s). One difference between Python and most of the other Smalltalk-model languages is that they use symbols or selectors or some other string-like type to name methods, while Python uses plain old strings. If you have print(:bar, foo.bar) obviously bar is the name of an attribute rather than normal text. Dropping selectors from the language turns out to cause a lot fewer problems than any Smalltalk devotee would have believed, just a few very small problems—like the one nameof is trying to fix. Meanwhile, unlike Smalltalk and most other languages with the same model, Python has optional static typing. The other major Smalltalk-model language that added optional static types is ObjectiveC—and one of the reasons was to improve the navigation and refactoring tools. For example, if you have a function that takes a `foo: Any` param (spelled `id foo` in ObjC) and there are three unrelated types that all have a `bar` method, the tool will tell you that it’s ambiguous which one you meant by `nameof bar` (spelled `@sel(bar)`), and it can suggest that you either specify a type for `foo`, or create an implicit ABC (a `@protocol` in ObjC terms) to own the method. If you do the first, renaming Foo.bar to baz will change the selector; if you do the latter, it will warn you that Foo.bar makes Foo conform to the Barable protocol that you defined and there are selectors in your program that depend on it being Barable, so do you want to break that or do you want to rename Barable.bar and all of the classes that implement it instead? If you do neither, it doesn’t guess, it tells you that there are two ambiguous uses of the selectors and lets you see the two uses of the selector or the three classes that define it, so you can proceed manually. Of course this means that an IDE, object browser, or standalone refactoring tool has to build a mapping from selector names to a list of implicit uses, explicit uses, and definitions (including knowing which definitions are inherited, and which are relied on by protocols) for the whole program. But that’s exactly what they do. That’s why RJBrowser takes a while to start up, and why Xcode is constantly running clang on bits of your code in the background as you edit. Couldn’t a Python tool just also keep track of every string and substring that has at least one match as a use or definition of an attribute? Yes. But I think it’s obvious why this is a lot more work and at least a little less useful. And that may be part of the reason Python has always had fewer refactoring tools available than Smalltalk, ObjC, etc., which is why nameof could be a useful addition.

On Feb 3, 2020, at 10:25, Andrew Barnert <abarnert@yahoo.com> wrote:
All that being said, I’m not sure _how_ useful it would be in practice. Python has a chicken-and-egg problem that C#, ObjC, etc. don’t. If the C#/ObjC devs add a new feature to their language, the Visual Studio/Xcode team next door adds a nameof-driven renaming feature to the refactoring tools in the IDE that 90% of C#/ObjC programmers use, and then then everyone who wants that feature starts using nameof. If the Python devs add nameof, PyCharm, PyDev, etc. may not take advantage of it, and they may already have an often-good-enough heuristic-guessing feature for people who don’t use it. If not many people start using it, there will be even less motivation for PyCharm to take advantage of it, etc. If a new feature has an obvious large benefit (and/or is fun enough to implement), like optional static typing, you can jump past that hurdle. If a new feature has other uses even without IDE support, like @dataclass, you can spiral over it. But nameof is neither; it might just be a dead-on-arrival feature that’s only ever used by a handful of large teams who build their own internal tools. (And that large internal-tool-building team could just define a builtin `def nameof(x: str): return x` to use while debugging and write an install-time or import-time transformer that just replaces every `nameof(x)` with `x` to eliminate the deployed runtime cost.) Add in the fact that most people use the newest version of C# or ObjC for any new project, while Python developers often stay a version or 3 behind, and a breaking change like this would probably need a __future__ and/or deprecation schedule on top of that, and the problem looks even worse. So, someone who wants this feature has to not only resolve all the confusion over what exactly is being proposed and how it helps, but also make the case that Python tools and Python programmers are likely to actually take advantage of it.

On Mon, Feb 3, 2020 at 3:58 AM Richard Damon <Richard@damon-family.org> wrote:
What you're actually asking for is a way for a refactoring tool to recognize that the string "bar" is a reference to the bar in foo.bar. You're NOT asking for the Python compiler to recognize that. There are lots of ways to do this. And Ricky Teachey's examples show that this is pretty ugly. On Mon, Feb 3, 2020 at 9:38 AM Ricky Teachey <ricky@teachey.org> wrote:
f"The field {nameof(foo)}.{nameof(foo.bar)} can be refactored." Here's my alternative: f"""The field {"foo.bar"} can be refactored.""" Since there's no real reason that you'd use {} around a literal string, we have our refactoring tool recognize that syntax as a variable reference. It has no net effect on the running code. If we don't want foo to be refactored, we write instead: f"""The field foo.{"bar"} can be refactored.""" And if we just want the string to reference "bar" but want to make sure it's foo.bar not something_else.bar, we could write this: f"""The field {"foo" and "bar"} can be refactored.""" --- Bruce

On 2020-02-04 3:33 a.m., Bruce Leban wrote:
Huh I didn't think of using string literals in fstrings like that. (altho, are "raw" fstrings a thing?) Anyway, I like how we've all been focusing on refactoring but how about this use-case instead: let's say one has a function that takes an object and an attribute name because Reasons: def create_attr(obj, attr): setattr(obj, attr, Thing(attr)) def screw_attr(obj, attr): getattr(obj, attr)._reset() delattr(obj, attr) class Foo: def __init__(self): create_attr(self, nameof self.__mangled) def bar(self): screw_attr(self, nameof self.__mangled) there's currently no way to get a string representation of a mangled attr and a nameof operator would let you do so.

A statement like print("bar", foo.bar) would be very hard to notice that
the "bar" match the foo.bar, while
print(nameof(foo.bar), foo.bar) makes the connection explicit.
Isn’t someone working on a “debug string” PEP that would mitigate this? Maybe not a full PEP: https://bugs.python.org/issue36774 And https://bugs.python.org/issue36817 I can’t quit tell where that is at — but it seems it may well address this problem. -CHB -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
participants (20)
-
Anders Hovmöller
-
Andrew Barnert
-
Bruce Leban
-
Calvin Spealman
-
Chris Angelico
-
Christopher Barker
-
Eric V. Smith
-
Ethan Furman
-
Greg Ewing
-
Johan Vergeer
-
Ned Batchelder
-
Random832
-
Rhodri James
-
Richard Damon
-
Richard Damon
-
Ricky Teachey
-
Ryan
-
Soni L.
-
Steven D'Aprano
-
Todd