Continuation of `__name__` or a builtin function for general name getting

Hi all, I'm not sure whether this idea has been discussed before or not, so I apologize in advanced if that's the case. Consider the behavior:
I'm arguing the behavior above is too brittle/limited and, considering that the name of the attribute is `__name__`, not entirely consistent with Python's AST. Consider:
f = lambda: True
x = f
At the first line, an ast.Assign would be created whose target is an ast.Name whose `id` is `f`. At the second line, an ast.Assign would be created whose target is an ast.Name whose `id` is `x`. However, as you can see `__name__` special method returns 'lambda' in both cases (just like it was defined https://docs.python.org/3/library/stdtypes.html#definition.__name__), whereas I think either it should have returned '<lambda>' and 'x' or a new function/attribute should exist that does so and more. For example, consider:
Now assume such a function exist and is called `name`. Then:
I think above example gives an idea of the behavior I'm proposing. I can implement it in a hacky way by parsing the block into ast and going through all the nodes that have an `id` or a `name` or `asname` etc, but this behavior wouldn't be pretty for run-time cases e.g. `itername` in the example above. Anyway I'd appreciate any input. P.S. I must confess that I can't think of a single case where having this function is the only way to do the job, if the job is sufficiently different from the specification of said function. It'd be only for the sake of convenience, and continuation of what already was there with `__name__`.

On Mon, Jun 19, 2017 at 7:38 AM, Alireza Rafiei <alireza.rafiei94@gmail.com> wrote:
The __name__ of a function has nothing to do with an Assign node, which is simply assigning a value to something. For instance, if you do:
f = "hello"
you wouldn't expect the string "hello" to have a __name__ - it's just a string. And a lambda function normally won't be assigned to anything. You use lambda when there isn't any name:
do_stuff(lambda q: q * 2 + 1)
and you use def when you want to assign it to a name:
def f(): return True
By the time the Assign operation gets performed, the function object - with all of its attributes, including __name__ - has been completely created. I'm not sure what your proposal would do to these kinds of situations, but it shouldn't be modifying the assigned object. ChrisA

The __name__ of a function has nothing to do with an Assign node,
I guess I should have framed it as a `quote` for python. You're absolutely right that it shouldn't be modifying the assigned object and it doesn't. I mentioned the Assign to say that in `x = f`, `x` has name as well, however `x.__name__` returns the name of `f` and not `x`. As for the `f = "hello"`, the value of the name "f" would be "hello" and the value of the name "hello" would be "hello". My proposal is to either change the behavior of `__name__` or have something similar that acts globally for all objects and types to get a quote-like behavior, provided that the operands of quotes are atomic. On Sun, Jun 18, 2017 at 2:46 PM, Chris Angelico <rosuav@gmail.com> wrote:

You're absolutely right! It should be changed to:
------ Hmm. So... after x = f, f.__name__ would be different from x.__name__? Yes. ------ I should have written my initial email more carefully! There's another mistake: However, as you can see `__name__` special method returns 'lambda' in both
It'd be inconsistent to say x.__name__ should return 'x' and f.__name__ should return '<lambda>'. To avoid further confusion of `name` the function with `__name__`, I take back what I said about `__name__` attribute. However I can't think of an inconsistency with a builtin function called `name` or `quote` or alike that behaves as described previously (name(x) would be 'x' and name(f) would be 'f' and name ("hello") would be "hello" etc.) and still appreciate any input on it. On Sun, Jun 18, 2017 at 3:24 PM, MRAB <python@mrabarnett.plus.com> wrote:

On Mon, Jun 19, 2017 at 8:47 AM, Alireza Rafiei <alireza.rafiei94@gmail.com> wrote:
Hmm. So... after x = f, f.__name__ would be different from x.__name__?
Yes.
There's a couple of major problems with that. The first is that, in Python, there is *absolutely no difference* between accessing an object via one form and via another. For example:
You can access y[0], z, q["spam"], and (most likely) probably, and they're all the same thing. Exactly the same object. So there's no way to do attribute access on that object and get different results. The second problem is that the current behaviour is extremely important. One such place is with function decorators, which frequently need to know the name of the function being worked on: def command(func): parser.add_parser(func.__name__) ... @command def spaminate(): ... Inside the decorator, "func.__name__" has to be the name of the function being decorated ("spaminate"), *not* "func". The function has an identity and a canonical name. Disrupting that would cause major difficulties for these kinds of decorators. ChrisA

On Mon, Jun 19, 2017 at 7:38 AM, Alireza Rafiei <alireza.rafiei94@gmail.com> wrote:
The __name__ of a function has nothing to do with an Assign node, which is simply assigning a value to something. For instance, if you do:
f = "hello"
you wouldn't expect the string "hello" to have a __name__ - it's just a string. And a lambda function normally won't be assigned to anything. You use lambda when there isn't any name:
do_stuff(lambda q: q * 2 + 1)
and you use def when you want to assign it to a name:
def f(): return True
By the time the Assign operation gets performed, the function object - with all of its attributes, including __name__ - has been completely created. I'm not sure what your proposal would do to these kinds of situations, but it shouldn't be modifying the assigned object. ChrisA

The __name__ of a function has nothing to do with an Assign node,
I guess I should have framed it as a `quote` for python. You're absolutely right that it shouldn't be modifying the assigned object and it doesn't. I mentioned the Assign to say that in `x = f`, `x` has name as well, however `x.__name__` returns the name of `f` and not `x`. As for the `f = "hello"`, the value of the name "f" would be "hello" and the value of the name "hello" would be "hello". My proposal is to either change the behavior of `__name__` or have something similar that acts globally for all objects and types to get a quote-like behavior, provided that the operands of quotes are atomic. On Sun, Jun 18, 2017 at 2:46 PM, Chris Angelico <rosuav@gmail.com> wrote:

You're absolutely right! It should be changed to:
------ Hmm. So... after x = f, f.__name__ would be different from x.__name__? Yes. ------ I should have written my initial email more carefully! There's another mistake: However, as you can see `__name__` special method returns 'lambda' in both
It'd be inconsistent to say x.__name__ should return 'x' and f.__name__ should return '<lambda>'. To avoid further confusion of `name` the function with `__name__`, I take back what I said about `__name__` attribute. However I can't think of an inconsistency with a builtin function called `name` or `quote` or alike that behaves as described previously (name(x) would be 'x' and name(f) would be 'f' and name ("hello") would be "hello" etc.) and still appreciate any input on it. On Sun, Jun 18, 2017 at 3:24 PM, MRAB <python@mrabarnett.plus.com> wrote:

On Mon, Jun 19, 2017 at 8:47 AM, Alireza Rafiei <alireza.rafiei94@gmail.com> wrote:
Hmm. So... after x = f, f.__name__ would be different from x.__name__?
Yes.
There's a couple of major problems with that. The first is that, in Python, there is *absolutely no difference* between accessing an object via one form and via another. For example:
You can access y[0], z, q["spam"], and (most likely) probably, and they're all the same thing. Exactly the same object. So there's no way to do attribute access on that object and get different results. The second problem is that the current behaviour is extremely important. One such place is with function decorators, which frequently need to know the name of the function being worked on: def command(func): parser.add_parser(func.__name__) ... @command def spaminate(): ... Inside the decorator, "func.__name__" has to be the name of the function being decorated ("spaminate"), *not* "func". The function has an identity and a canonical name. Disrupting that would cause major difficulties for these kinds of decorators. ChrisA
participants (3)
-
Alireza Rafiei
-
Chris Angelico
-
MRAB