[Python-ideas] Re: addition of "nameof" operator
On Jan 30, 2020, at 11:20, Johan Vergeer wrote: > > 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. 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: > ```python > def my_factory(class_name: str): >if class_name == "Foo": >return Foo() >if class_name == "Bar": >return Bar() > ``` 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). > ## 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__`. 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.) > ## 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" If you compile nameof(foo.bar) t
[Python-ideas] Re: Allow spaces between string prefix and the string literal
On Thu, Jan 30, 2020 at 12:39:29AM +0300, Mikhail V wrote: > I would like to see possibility to put spaces > between the string prefix and the string literal > so I could write e.g. like this: > > print (f "x: {x}") > > IMO it would help with legibility especially > noticable with by proportional fonts. If you are having problems with your source code being less legible and harder to read due to the use of proportional fonts, rather than asking to change the language, you should stop using proportional fonts for reading code. Or at least choose a better font. If your chosen font makes f" and f' illegible, then you have chosen badly. -- Steven ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/H6DSXFBIAREJBVB6ZVLP3CZK7RL46GHH/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Allow spaces between string prefix and the string literal
The problem is that's ambiguous to the grammar whether you truly mean 'f' as a prefix or 'f' as a variable and just happened to type something wrong. And then debugging that would be horrible. So even if the grammar to support it, I'm -1 on the idea. On Wed, Jan 29, 2020 at 1:41 PM Mikhail V wrote: > I would like to see possibility to put spaces > between the string prefix and the string literal > so I could write e.g. like this: > > print (f "x: {x}") > > IMO it would help with legibility especially > noticable with by proportional fonts. > > Mikhail > ___ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-le...@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at > https://mail.python.org/archives/list/python-ideas@python.org/message/OXR2HHUYZYXJXNOL4INTOAOPXJWWCZBA/ > Code of Conduct: http://python.org/psf/codeofconduct/ > ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/FNN6LK4DKQDCKLSULINBW524MX2V7N3H/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: addition of "nameof" operator
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__' ``` ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas