[Python-ideas] Re: addition of "nameof" operator

2020-02-04 Thread Chris Angelico
On Wed, Feb 5, 2020 at 5:14 AM Christopher Barker  wrote:
>
> > 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.
>

Landed.

>>> f"{3+.9=}"
'3+.9=3.9'

But it's insufficient in itself for the OP's use-case.

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


[Python-ideas] Re: addition of "nameof" operator

2020-02-04 Thread Christopher Barker
> 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
___
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/7YPEX57I2TB37NLGFXVLABRKO3SKXQ23/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-04 Thread Soni L.



On 2020-02-04 3:33 a.m., Bruce Leban wrote:



Here is a much more readable alternative which has the advantage that 
it is already supported by Python. I'm going to show a harder example 
where I want to reference foo.bar and allow both foo and bar to be 
refactored. Here's the original proposal:


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


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.







___
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/J2DZZLAOV72SS4XXJISX7KPZNJPYUZVE/
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/UXTHIU2ZPJEF3GK2G7QSNSURU53R66WH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-03 Thread Bruce Leban
On Mon, Feb 3, 2020 at 3:58 AM Richard Damon 
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.
>

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  wrote:

> 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().
>
> 
>
> 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.
> """
> *...*logging.exception(f"failed to log {func_name!r} call; is 
> {cls_name}.{log_param_name} set correctly?")
>
> *Bottom line: refactoring remains a chore. The win is minimal. Do nothing
> option is preferred.*
>
> Here is a much more readable alternative which has the advantage that it
is already supported by Python. I'm going to show a harder example where I
want to reference foo.bar and allow both foo and bar to be refactored.
Here's the original proposal:

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



>
___
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/J2DZZLAOV72SS4XXJISX7KPZNJPYUZVE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-03 Thread Andrew Barnert via Python-ideas
On Feb 3, 2020, at 10:25, Andrew Barnert  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.

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-ideas] Re: addition of "nameof" operator

2020-02-03 Thread Andrew Barnert via Python-ideas
On Feb 3, 2020, at 03:59, Richard Damon  wrote:
> 
> On 2/3/20 12:02 AM, Bruce Leban wrote:
>> 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
> 
> 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).

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.

___
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 

[Python-ideas] Re: addition of "nameof" operator

2020-02-03 Thread Ricky Teachey
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 

[Python-ideas] Re: addition of "nameof" operator

2020-02-03 Thread Richard Damon

On 2/3/20 12:02 AM, Bruce Leban wrote:

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


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
___
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/COJJ4EG4B5J2DKXZIZSQV7D2USZ3QGCS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Bruce Leban
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
___
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/S5C4KQTF3KFX2DRTLTEO22AE7MPSKDMX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Andrew Barnert via Python-ideas
> On Feb 2, 2020, at 09:14, Johan Vergeer  wrote:
> 
> 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.

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).___
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/KGVHNV25N5CKKZZ6YO3JKCYTLSVXQIGI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Guido van Rossum
That's based on my observation of how the discussion went. I have been
participating in such discussions for 30 years now and I can usually tell
how it will end long before most other participants. So I actually cringe
when I see discussion go on beyond the point of usefulness. This is such a
case, where I feel it's fair to tell the participants to stop or take it
elsewhere.

On Sun, Feb 2, 2020 at 01:39 Johan Vergeer  wrote:

> Hi Guido,
>
> This thread had a lot of comments so far, both people that are pro and
> con.
> To be honest, a lot of you are a smarter and more experienced than me, so
> I receive all of it as learning moments.
>
> What I am wondering about is your personal motivation to say the feature
> won't every be a part of Python. Would you mind to share that?
>
> Kind regards,
>
> Johan Vergeer
> ___
> 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/B6Q2LXIXGP42US3J6ES4HZYAEGW5G724/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
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/OGWF25NFLIYGKBAQRMN7FN5RYVMTELUP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Soni L.




On 2020-02-02 2:00 p.m., Johan Vergeer wrote:

This would look pretty nice when it would just be used in f-strings.

My proposal isn't just about f-strings though. It should also allow developers 
to get the name of a variable, class, method or function anywhere else.


where do you want to do it that returning a string isn't good enough?

fstrings return a string. they seem perfect for this.

or are you trying to say you don't like the extra symbols around it? tbh 
I don't either. ideally I'd go for f"{#foo.}bar" but oh well, convincing 
ppl of this is gonna be harder than "just let it have comments" .-.


(fwiw, f"{#}Foo" would also be usable, for top-level elements and stuff.)


___
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/H6ULMWVE6G57O2VKYPYKSYGZSW232VAY/
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/TKRCLAGRTAW2PXEKPIJBCUITWVK5G3QK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Johan Vergeer
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?
___
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/KOKV2SC4YONKPFYQNMZWB5YL4NMB7ZA4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Johan Vergeer
This would look pretty nice when it would just be used in f-strings. 

My proposal isn't just about f-strings though. It should also allow developers 
to get the name of a variable, class, method or function anywhere else.
___
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/H6ULMWVE6G57O2VKYPYKSYGZSW232VAY/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Soni L.



On 2020-02-02 12:08 p.m., Jeff Allen wrote:

On 01/02/2020 02:48, Richard Damon wrote:

On 1/31/20 9:28 PM, Christopher Barker wrote:

I am really confused by this whole thread:


My understanding is that the impetus of the request is that if you 
start from an expression like nameof(foo.bar) to get to "bar" then if 
you refactor your code you have a chance that the tool will be able 
to see the variable expression foo.bar, and process that like other 
references to the item, and thus be able to change it. Just using the 
string "bar" would be very hard to see the connection between foo.bar 
and "bar".


Maybe I haven't been paying attention but, if accurate, this is the 
most helpful explanation in the thread.


Some sort of conventional mark-up for variable names seems more 
appropriate than a (pseudo-)function. Possibly something the compiler 
is made to ignore in strings, but that the IDE treats as identifying a 
variable name. It would work in comments too. Single quotes do it 
pretty well, making it a coding standards and IDEs question.




Hm.

Well here's my take:

f"{''#foo.}bar"

let us have comments in fstrings :p

I'd love to have a nameof that errors at runtime tho.


Jeff Allen

___
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/CDMD4Z3U3VZJSN2MB74MMGNEVNFZ3GLI/
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/IKF6HONJG5KWQMQQ5EV5MEJ52LLQR6OI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Jeff Allen

On 01/02/2020 02:48, Richard Damon wrote:

On 1/31/20 9:28 PM, Christopher Barker wrote:

I am really confused by this whole thread:


My understanding is that the impetus of the request is that if you 
start from an expression like nameof(foo.bar) to get to "bar" then if 
you refactor your code you have a chance that the tool will be able to 
see the variable expression foo.bar, and process that like other 
references to the item, and thus be able to change it. Just using the 
string "bar" would be very hard to see the connection between foo.bar 
and "bar".


Maybe I haven't been paying attention but, if accurate, this is the most 
helpful explanation in the thread.


Some sort of conventional mark-up for variable names seems more 
appropriate than a (pseudo-)function. Possibly something the compiler is 
made to ignore in strings, but that the IDE treats as identifying a 
variable name. It would work in comments too. Single quotes do it pretty 
well, making it a coding standards and IDEs question.


Jeff Allen

___
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/CDMD4Z3U3VZJSN2MB74MMGNEVNFZ3GLI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-02 Thread Johan Vergeer
Hi Guido,

This thread had a lot of comments so far, both people that are pro and con. 
To be honest, a lot of you are a smarter and more experienced than me, so I 
receive all of it as learning moments.

What I am wondering about is your personal motivation to say the feature won't 
every be a part of Python. Would you mind to share that?

Kind regards,

Johan Vergeer
___
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/B6Q2LXIXGP42US3J6ES4HZYAEGW5G724/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-01 Thread Anders Hovmöller



> On 2 Feb 2020, at 01:00, Christopher Barker  wrote:
> 
> And no one answered my questions about what it would do in all the, very 
> common cases where an object doesn't ahve a name, opr more than one.

This question has been answered multiple times. It's not about the object, it's 
about the variable. Variables have names. Objects do not as you point out. 

/ Anders 
___
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/IF6HVRNZEQFUGNWOY3VRG3S2S5IFBXJK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-01 Thread Christopher Barker
On Fri, Jan 31, 2020 at 9:50 PM Richard Damon 
wrote:

> On 1/31/20 9:28 PM, Christopher Barker wrote:
> > I am really confused by this whole thread:
>



> My understanding is that the impetus of the request is that if you start
> from an expression like nameof(foo.bar) to get to "bar" then if you
> refactor your code you have a chance that the tool will be able to see
> the variable expression foo.bar, and process that like other references
> to the item, and thus be able to change it. Just using the string "bar"
> would be very hard to see the connection between foo.bar and "bar".
>

Huh? you only njeed to know the name of something as a string is yuou are
doing metaprogramming of some sort -- which is a great feature, but not
everyday code.

So someone wants this so that they can more easily *refactor* code that
isn't very common? I'm betting even more cofused.

And no one answered my questions about what it would do in all the, very
common cases where an object doesn't ahve a name, opr more than one.

More confused than ever..

- CHB



-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/UTVNVZEADVINX4MVVGUHCBUFMUSV5AG6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-01 Thread Guido van Rossum
The whole feature.

On Sat, Feb 1, 2020 at 14:35 Greg Ewing  wrote:

> On 2/02/20 6:12 am, Guido van Rossum wrote:
>
> > Alex, this is not ever going to be added to Python,
>
> For clarity, are you rejecting the whole idea of a "nameof" feature,
> or just bytecode-hack implementations of it?
>
> --
> Greg
> ___
> 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/F7357T6R7B2QKVBQI2JOTYFAKNEV7R5X/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
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/QWSIPNDHXWP6LJOCYDRFMMIO3QLTLLI7/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-01 Thread Greg Ewing

On 2/02/20 6:12 am, Guido van Rossum wrote:


Alex, this is not ever going to be added to Python,


For clarity, are you rejecting the whole idea of a "nameof" feature,
or just bytecode-hack implementations of it?

--
Greg
___
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/F7357T6R7B2QKVBQI2JOTYFAKNEV7R5X/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-01 Thread Guido van Rossum
>>
>> -- Forwarded message --
>> From: Chris Angelico 
>> To: python-ideas 
>> Cc:
>> Bcc:
>> Date: Sat, 1 Feb 2020 10:22:13 +1100
>> Subject: [Python-ideas] Re: Proposal for an additional type system
>> On Sat, Feb 1, 2020 at 10:06 AM  wrote:
>> >
>> > The types in most programming languages are only technical types. If a
>> variable has a type, you may know that it is of type integer or double, but
>> you don't know if it's a length or an area.
>> > The types required are semantic types.
>> >
>> > stypes:
>> > length
>> > area
>> > time
>> > speed
>> > scalar
>> >
>> > allowed expressions:
>> > length = length
>> > length + length : length
>> > time = time
>> > time + time : time
>> > scalar * length : length
>> > scalar * time : time
>> > sqrt(area) : length
>> > speed = speed
>> > length / time : speed
>> >
>>
>> This doesn't need a dedicated type system. Those are actual types,
>> representing units - though you've omitted the actual units. Create a
>> system of classes with actual units, for instance:
>>
>> class Meter(int):
>> ...
>>
>> class Second(int):
>> ...
>>
>> Define the operations that are valid on each of these, and what they
>> return. Define the valid comparisons (for instance, 3 meters is not
>> less than 4 seconds, and that doesn't make sense).
>>
>> Python's normal type system is quite powerful, and can handle this
>> smoothly.
>>
>> (Once you've had a shot at building this yourself, poke around on PyPI
>> and see what already exists.)
>>
>> ChrisA
>>
>>
>> ---------- Forwarded message --
>> From: Greg Ewing 
>> To: python-ideas@python.org
>> Cc:
>> Bcc:
>> Date: Sat, 01 Feb 2020 12:33:28 +1300
>> Subject: [Python-ideas] Re: addition of "nameof" operator
>> On 1/02/20 6:15 am, Richard Damon 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,
>>
>> 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
>>
>>
>>
>> ------ Forwarded message --
>> From: Alex Hall 
>> To: python-ideas@python.org
>> Cc:
>> Bcc:
>> Date: Sat, 1 Feb 2020 01:52:38 +0200
>> Subject: [Python-ideas] Re: addition of "nameof" operator
>> Here's a simple runtime implementation that doesn't require any
>> dependencies or source code access:
>>
>> import dis
>> import inspect
>> from functools import lru_cache
>>
>>
>> def nameof(_):
>> frame = inspect.currentframe().f_back
>> return _nameof(frame.f_code, frame.f_lasti)
>>
>>
>> @lru_cache
>> def _nameof(code, offset):
>> instructions = list(dis.get_instructions(code))
>> (current_instruction_index, current_instruction), = (
>> (index, instruction)
>> for index, instruction in enumerate(instructions)
>> if instruction.offset == offset
>> )
>> assert current_instruction.opname == "CALL_FUNCTION"
>> name_instruction = instructions[current_instruction_index - 1]
>> assert name_instruction.opname.startswith("LOAD_")
>> return name_instruction.argrepr
>>
>>
>> def test():
>> print(nameof(dis))
>> print(nameof(dis.get_instructions))
>> x = 1
>> print(nameof(x))
>>
>>
>> if __name__ == '__main__':
>> test()
>>
>>
>>
>> -- Forwarded message --
>> From: "Steven D'Aprano" 
>> To: python-ideas@python.org
>> Cc:
>> Bcc:
>> Date: Sat, 1 Feb 2020 11:52:21 +1100
>> Subject: [Python-ideas] Re: addition of "

[Python-ideas] Re: addition of "nameof" operator

2020-02-01 Thread Richard Damon

On 1/31/20 10:58 PM, Andrew Barnert via Python-ideas wrote:


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.


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
___
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/TJLFZANF54K7JZM6NBQC3JI7GCCUKKPV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-02-01 Thread Alex Hall
> > sqrt(area) : length
> > speed = speed
> > length / time : speed
> >
>
> This doesn't need a dedicated type system. Those are actual types,
> representing units - though you've omitted the actual units. Create a
> system of classes with actual units, for instance:
>
> class Meter(int):
> ...
>
> class Second(int):
>     ...
>
> Define the operations that are valid on each of these, and what they
> return. Define the valid comparisons (for instance, 3 meters is not
> less than 4 seconds, and that doesn't make sense).
>
> Python's normal type system is quite powerful, and can handle this
> smoothly.
>
> (Once you've had a shot at building this yourself, poke around on PyPI
> and see what already exists.)
>
> ChrisA
>
>
> -- Forwarded message --
> From: Greg Ewing 
> To: python-ideas@python.org
> Cc:
> Bcc:
> Date: Sat, 01 Feb 2020 12:33:28 +1300
> Subject: [Python-ideas] Re: addition of "nameof" operator
> On 1/02/20 6:15 am, Richard Damon 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,
>
> 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
>
>
>
> -- Forwarded message --
> From: Alex Hall 
> To: python-ideas@python.org
> Cc:
> Bcc:
> Date: Sat, 1 Feb 2020 01:52:38 +0200
> Subject: [Python-ideas] Re: addition of "nameof" operator
> Here's a simple runtime implementation that doesn't require any
> dependencies or source code access:
>
> import dis
> import inspect
> from functools import lru_cache
>
>
> def nameof(_):
> frame = inspect.currentframe().f_back
> return _nameof(frame.f_code, frame.f_lasti)
>
>
> @lru_cache
> def _nameof(code, offset):
> instructions = list(dis.get_instructions(code))
> (current_instruction_index, current_instruction), = (
> (index, instruction)
> for index, instruction in enumerate(instructions)
> if instruction.offset == offset
> )
> assert current_instruction.opname == "CALL_FUNCTION"
> name_instruction = instructions[current_instruction_index - 1]
> assert name_instruction.opname.startswith("LOAD_")
> return name_instruction.argrepr
>
>
> def test():
> print(nameof(dis))
> print(nameof(dis.get_instructions))
> x = 1
> print(nameof(x))
>
>
> if __name__ == '__main__':
> test()
>
>
>
> -- Forwarded message --
> From: "Steven D'Aprano" 
> To: python-ideas@python.org
> Cc:
> Bcc:
> Date: Sat, 1 Feb 2020 11:52:21 +1100
> Subject: [Python-ideas] Re: addition of "nameof" operator
> On Sat, Feb 01, 2020 at 01:52:38AM +0200, Alex Hall wrote:
>
> > Here's a simple runtime implementation that doesn't require any
> > dependencies or source code access:
> >
> > import dis
>
> So this is not likely to ever work in IronPython or Jython.
>
> There are no stability guarantees about the byte-code generated by
> CPython, so you may be chasing a moving target here.
>
> You ought to test your code before posting, because I've tried it in
> 3.5, 3.7 and 3.8 and I get the same error each time:
>
> TypeError: Expected maxsize to be an integer or None
>
> which is a simple error in the call to the lru_cache decorator. After
> fixing that, I tried it again in 3.7 and I get this:
>
> >>> x = 1
> >>> nameof.nameof(x)
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "/home/srv-steve/python/nameof.py", line 7, in nameof
> return _nameof(frame.f_code, frame.f_lasti)
>   File "/home/srv-steve/python/nameof.py", line 17, in _nameof
> assert current_instruction.opname == "CALL_FUNCTION"
> AssertionError
>
>
> --
> Steven
>
>
> -- Forwarded message --
> From: Christopher Barker 
> To: "Steven D'Aprano" 
> Cc: python-ideas@pyth

[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Steven D'Aprano
On Thu, Jan 30, 2020 at 07:17:34PM -, 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.

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.


> ## 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()
> ```

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.)

 
> 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()
> ```

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.


> 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__`.

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
___
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/OXIOLKAUXIWJNPA2BAIZLXN35DBEJ77L/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Andrew Barnert via Python-ideas
On Jan 31, 2020, at 19:30, Soni L.  wrote:
> 
> 
>> On 2020-02-01 12:00 a.m., Andrew Barnert wrote:
>> On Jan 31, 2020, at 14:51, Soni L.  wrote:
>> >>> On 2020-01-31 2:36 p.m., Andrew Barnert 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
>> 
>> > 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.
> 
> Yes, really. It's dynamic, so it must pay attention to the context it's being 
> used in.

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.

>> > > But here's the thing -- C# is statically checked. Python is dynamically 
>> > > checked. (and yes, Python *does* have type checking, among other things.)
>> 
>> 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.
>> 
>> 
> 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!*

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?

> Additionally those languages have null, so you could do something along the 
> lines of:
> 
> Spam dummy = null;
> nameof dummy.eggs

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 

[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Andrew Barnert via Python-ideas
Sorry, sent early… ignore that and try this version.

> 
> On Jan 31, 2020, at 19:58, Andrew Barnert  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.

___
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/I77NGRZJWPCZMY7JLPWUKD5CIUV4FLSN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Andrew Barnert via Python-ideas
Here’s a concrete proposal.

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

Rationale:

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

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

For example:

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

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

Similarly for this example:

rpc.register(nameof spam, spam)

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

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

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




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

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

Grammar:

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

Semantics:

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

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

A static type checker may be able to 

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

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/4GWYKCEVW3XUU52JAGXXGC3DEFYDODJM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Soni L.



On 2020-02-01 12:00 a.m., Andrew Barnert wrote:

On Jan 31, 2020, at 14:51, Soni L.  wrote:
>>> On 2020-01-31 2:36 p.m., Andrew Barnert 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

> 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.


Yes, really. It's dynamic, so it must pay attention to the context it's 
being used in.




>> 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?
> 
> But here's the thing -- C# is statically checked. Python is dynamically checked. (and yes, Python *does* have type checking, among other things.)


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.



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 

[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Andrew Barnert via Python-ideas
On Jan 31, 2020, at 14:51, Soni L.  wrote:
>>> On 2020-01-31 2:36 p.m., Andrew Barnert 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

> 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.

>> 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?
> 
> But here's the thing -- C# is statically checked. Python is dynamically 
> checked. (and yes, Python *does* have type checking, among other things.)

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.

___
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/DYQEUXC7ACKIRFQI4CI7SJGMP6TG33FZ/
Code of 

[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Richard Damon

On 1/31/20 9:28 PM, Christopher Barker wrote:

I am really confused by this whole thread:

(I know this has all been said in this thread, but I’m summarizing to 
get us on the same page for the following comments)


Python has names, and it has values (objects, whatever) when we write 
Python, we bind names to values with the = operator. (And other 
namespace trickery). Some types of objects do have a __name__ 
attribute: classes, functions created with def.


But that name is only sometimes the same as the name(s) it might be 
bound to in any given namespace. So what the heck is nameof() supposed 
to mean? A few examples:


>>> x = 5
>>>nameof(x)

OK, I suppose that’s “x” — but what is the point of that? You have to 
know the name already.


What about:

y = 5
x = 5
(Or x = y)

What is nameof(x) And nameof(y)?

What about nameof(5)?

Now:

def fun():
    pass

I suppose nameof(fun) is “fun”, but again, is that useful?

And now:

Fred = fun

What’s nameof(Fred)

If it’s “Fred” then again, useless.

If it’s “fun” then what about x and y before?

And:

def fun():
    y = something
    return y

lst.append(fun())

nameof(lst[-1])



In short, if it means “what is the name of this name” that seems 
completely useless?


If it means: what name is this object bound to in this namespace? Than 
I can see how one might think that would be useful, but the answer 
could be:


No name at all
More than one name
A name different than the object’s __name__

And then there is the question of the local vs global namespace, the 
list goes on.


This thread has been going on a while:

What am I missing?

-CHB

My understanding is that the impetus of the request is that if you start 
from an expression like nameof(foo.bar) to get to "bar" then if you 
refactor your code you have a chance that the tool will be able to see 
the variable expression foo.bar, and process that like other references 
to the item, and thus be able to change it. Just using the string "bar" 
would be very hard to see the connection between foo.bar and "bar".


--
Richard Damon
___
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/SLUI4AHPPDS3FB35SZ5EL6QX4ZIA4HDB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Christopher Barker
I am really confused by this whole thread:

(I know this has all been said in this thread, but I’m summarizing to get
us on the same page for the following comments)

Python has names, and it has values (objects, whatever) when we write
Python, we bind names to values with the = operator. (And other namespace
trickery). Some types of objects do have a __name__ attribute: classes,
functions created with def.

But that name is only sometimes the same as the name(s) it might be bound
to in any given namespace. So what the heck is nameof() supposed to mean? A
few examples:

>>> x = 5
>>>nameof(x)

OK, I suppose that’s “x” — but what is the point of that? You have to know
the name already.

What about:

y = 5
x = 5
(Or x = y)

What is nameof(x) And nameof(y)?

What about nameof(5)?

Now:

def fun():
pass

I suppose nameof(fun) is “fun”, but again, is that useful?

And now:

Fred = fun

What’s nameof(Fred)

If it’s “Fred” then again, useless.

If it’s “fun” then what about x and y before?

And:

def fun():
y = something
return y

lst.append(fun())

nameof(lst[-1])



In short, if it means “what is the name of this name” that seems completely
useless?

If it means: what name is this object bound to in this namespace? Than I
can see how one might think that would be useful, but the answer could be:

No name at all
More than one name
A name different than the object’s __name__

And then there is the question of the local vs global namespace, the list
goes on.

This thread has been going on a while:

What am I missing?

-CHB







>
>
-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/ZDMNZVJJMX26M5B2VUWRLC6NDKUXTH4J/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Steven D'Aprano
On Sat, Feb 01, 2020 at 01:52:38AM +0200, Alex Hall wrote:

> Here's a simple runtime implementation that doesn't require any
> dependencies or source code access:
> 
> import dis

So this is not likely to ever work in IronPython or Jython.

There are no stability guarantees about the byte-code generated by 
CPython, so you may be chasing a moving target here.

You ought to test your code before posting, because I've tried it in 
3.5, 3.7 and 3.8 and I get the same error each time:

TypeError: Expected maxsize to be an integer or None

which is a simple error in the call to the lru_cache decorator. After 
fixing that, I tried it again in 3.7 and I get this:

>>> x = 1
>>> nameof.nameof(x)
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/srv-steve/python/nameof.py", line 7, in nameof
return _nameof(frame.f_code, frame.f_lasti)
  File "/home/srv-steve/python/nameof.py", line 17, in _nameof
assert current_instruction.opname == "CALL_FUNCTION"
AssertionError


-- 
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/25TBO3VYZIVMAN36K5NTNRZ5VUGVIBCD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Alex Hall
Here's a simple runtime implementation that doesn't require any
dependencies or source code access:

import dis
import inspect
from functools import lru_cache


def nameof(_):
frame = inspect.currentframe().f_back
return _nameof(frame.f_code, frame.f_lasti)


@lru_cache
def _nameof(code, offset):
instructions = list(dis.get_instructions(code))
(current_instruction_index, current_instruction), = (
(index, instruction)
for index, instruction in enumerate(instructions)
if instruction.offset == offset
)
assert current_instruction.opname == "CALL_FUNCTION"
name_instruction = instructions[current_instruction_index - 1]
assert name_instruction.opname.startswith("LOAD_")
return name_instruction.argrepr


def test():
print(nameof(dis))
print(nameof(dis.get_instructions))
x = 1
print(nameof(x))


if __name__ == '__main__':
test()
___
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/LRWW62OIJ4LVS4PTXRN23CLB5VBRWZ7Y/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Greg Ewing

On 1/02/20 6:15 am, Richard Damon 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,


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
___
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/R5UHSSKQDD4LNMFOMB7LYRBYMH4H2EFR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Soni L.



On 2020-01-31 2:36 p.m., Andrew Barnert wrote:

On Jan 31, 2020, at 08:03, Soni L.  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.)


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


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.



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?


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.

___
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/57TPPA7KCRDWDWE3WYDUQLXJSCTRYWBF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Andrew Barnert via Python-ideas
On Jan 31, 2020, at 08:03, Soni L.  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.)

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?
___
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/62GL6YJWPE6CKH7BLIYYQNNGAZLXBWEB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Richard Damon
On Jan 31, 2020, at 11:01 AM, Soni L.  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.)
> 
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.
___
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/NKRZ4POX6RUODA32RBWYNATMXR6W6OM5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-31 Thread Soni L.



On 2020-01-30 7:17 p.m., Andrew Barnert via Python-ideas wrote:

On Jan 30, 2020, at 11:20, Johan Vergeer  wrote:

> ## 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) 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.)




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.)

___
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/RJWWSGIWUJ4OUNQDSAK7JAGE2VSOJYRD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-30 Thread Andrew Barnert via Python-ideas
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) 

[Python-ideas] Re: addition of "nameof" operator

2020-01-30 Thread Johan Vergeer
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

[Python-ideas] Re: addition of "nameof" operator

2020-01-23 Thread Johan Vergeer
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.
___
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/BGYKWTLGPQR34DTOVF52HPF5NIZ5OCQN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Random832
On Tue, Jan 21, 2020, at 16:32, 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?

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)
___
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/7IZRVFY2QB5LFDYL4MWL7L6I7GRV5SFP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Ned Batchelder

On 1/22/20 8:05 AM, Anders Hovmöller wrote:



On 22 Jan 2020, at 13:23, Rhodri James  wrote:

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.

Does it? How? 
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/nameof
 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?


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.
___
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/KZC46DAIGHOM4RBUHV2NDDQ7GURJ6V5G/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Anders Hovmöller


> On 22 Jan 2020, at 14:39, Alex Hall  wrote:
> 
> 
> You can achieve this now with my executing library: 
> https://github.com/alexmojaki/executing
> 
> ```
> import ast
> import inspect
> 
> import executing
> 
> 
> def nameof(_):
> frame = inspect.currentframe().f_back
> call = executing.Source.executing(frame).node
> arg = call.args[0]
> if isinstance(arg, ast.Name):
> return arg.id
> elif isinstance(arg, ast.Attribute):
> return arg.attr
> else:
> raise SyntaxError
> 
> 
> foo = 3
> print(nameof(foo))
> 
> print(f"{nameof(ast.Add)} = {ast.Add}")
> ```
> 
> Other tricks of this nature can be found here: 
> https://github.com/alexmojaki/sorcery

That's pretty cool!___
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/CDE44AP7P3ANO656EUQ4DOGQSXNWMWG3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Alex Hall
You can achieve this now with my executing library:
https://github.com/alexmojaki/executing

```
import ast
import inspect

import executing


def nameof(_):
frame = inspect.currentframe().f_back
call = executing.Source.executing(frame).node
arg = call.args[0]
if isinstance(arg, ast.Name):
return arg.id
elif isinstance(arg, ast.Attribute):
return arg.attr
else:
raise SyntaxError


foo = 3
print(nameof(foo))

print(f"{nameof(ast.Add)} = {ast.Add}")
```

Other tricks of this nature can be found here:
https://github.com/alexmojaki/sorcery
___
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/XSTWIXDFPSMMIGSXVPKEEGTMFDQ66JUM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Chris Angelico
On Wed, Jan 22, 2020 at 11:57 PM Richard Damon  wrote:

> 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.
>

For the record, this sort of debugging purpose IS important to Python,
and f-strings have a special facility for this:

>>> x, y = 1234.5, "spam"
>>> print(f"Before flurblization: {x=} {y=}")
Before flurblization: x=1234.5 y='spam'

ChrisA
___
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/RKAGBJTBZP6N2ULIRJIPOCXYPG2JZ4JK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Anders Hovmöller


> On 22 Jan 2020, at 13:23, Rhodri James  wrote:
> 
> 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.

Does it? How? 
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/nameof
 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 
___
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/7SS7MB5DBURCGLSUN47HXOD7P3NH3OBK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Richard Damon

On 1/22/20 7:08 AM, Rhodri James wrote:

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.


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
___
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/RSBOLYY7JEIMOMXVCB5MBKZFWMNUNCIR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Rhodri James

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
___
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/YA6THD7VW7CP64IPDB4AVH3YUE5YYG4X/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Anders Hovmöller



> On 22 Jan 2020, at 11:50, Steven D'Aprano  wrote:
> 
> But what should these things do?
> 
>x = y = z = 1
>nameof(1)

Syntax error.

>nameof(z)

"z"

>nameof("Gumby")

Syntax error.

>nameof(mysequence[0])

Syntax error.

> 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.

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. 

/ Anders 
___
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/U52FTXEB6553QSOTYWDYWAD4HL6FV36D/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Steven D'Aprano
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
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email 

[Python-ideas] Re: addition of "nameof" operator

2020-01-22 Thread Anders Hovmöller


> On 21 Jan 2020, at 22:50, Andrew Barnert via Python-ideas 
>  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 
___
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/MOUV45AYQPFE7TDXDIKT3JNGBLSFRTWD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Ethan Furman

On 01/21/2020 02:08 PM, Chris Angelico 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.


Gotcha, thanks.  I'm still unsure what the OP wants, though.

--
~Ethan~
___
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/BMTYINVLGPRON2MITEFHTYDASGB5CMUL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Chris Angelico
On Wed, Jan 22, 2020 at 9:04 AM Ethan Furman  wrote:
>
> On 01/21/2020 11:25 AM, Chris Angelico wrote:
>
> > 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.
>
> 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!)
>

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
___
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/P2AQBDQ4F2YYYSAMDUFKZNNKXFEP3HBU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Ethan Furman

On 01/21/2020 11:25 AM, Chris Angelico wrote:


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.


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~
___
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/EX4AFMICCTBUCHUKQ2HYCPQDL2T236BG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Eric V. Smith


On 1/21/2020 4:50 PM, Eric V. Smith wrote:

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.



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

___
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/JOXQOCEWZFJF5L3CH4YVQVSHNXIBZCMP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Eric V. Smith

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
___
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/AYZPTHSA65RWT2S5UOB7ERRTNSFX3SJU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Andrew Barnert via Python-ideas
On Jan 21, 2020, at 13:32, Andrew Barnert  wrote:
> 
> On Jan 21, 2020, at 10:48, Johan Vergeer  wrote:
>> 
>>   def __repr__(self):
>>   return f"{nameof(Person)}({nameof(self.name)}: {self.name}, 
>> {nameof(self.age)}: {self.age})"
> 
> 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?

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.
___
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/AB5HVE4XJKZ57PR2RIYABVLMBUIEESIX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Andrew Barnert via Python-ideas
On Jan 21, 2020, at 10:48, Johan Vergeer  wrote:
> 
> 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/nameof).
> 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 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.

___
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/HGSFWSUNM2BAVTXJRB3GMOUS2IQMHEVL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Calvin Spealman
Why? That looks like more code to accomplish exactly the same thing.

On Tue, Jan 21, 2020 at 1:49 PM Johan Vergeer 
wrote:

> 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/nameof
> ).
> 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?
> ___
> 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/UUFFAI3FZMQRVPDCUPZEOAZCRNXKWFDE/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>

-- 

CALVIN SPEALMAN

SENIOR QUALITY ENGINEER

cspea...@redhat.com  M: +1.336.210.5107
[image: https://red.ht/sig] 
TRIED. TESTED. TRUSTED. 
___
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/JD4NNVVHUZGUJXLG7C7V2YYR3VQELO2I/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Ryan
I believe Python 3.8's '=' f-string specifier (
https://docs.python.org/3/whatsnew/3.8.html#f-strings-support-for-self-documenting-expressions-and-debugging)
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  wrote:

> 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/nameof
> ).
> 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?
> ___
> 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/UUFFAI3FZMQRVPDCUPZEOAZCRNXKWFDE/
> 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/VMTXL42JIFNVCXTTCHX74LFYFVY4QHRY/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Ned Batchelder

On 1/21/20 3:11 PM, Ned Batchelder wrote:

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?





Oops, sorry, just after sending, I understood: the nameof expression 
would raise an error if you changed the name of self.name and left it 
behind.  That seems like a long way to go to get that effect.


--Ned.
___
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/IHXME3F5XEQZAN6JSK2PMC4UOWV7AVSF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Ned Batchelder

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.
___
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/S2CC2CYATU3PTTMT5675WA5F7GGWVZ3K/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Chris Angelico
On Wed, Jan 22, 2020 at 6:43 AM Eric V. Smith  wrote:
>
> On 1/21/2020 2:25 PM, Chris Angelico wrote:
> >
> > 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.
>
> reprlib would seem to be the place for this, if it's not already there.
>

And... I did not know about that module. Cool! That would be superior
to a docs recipe. I'll spin this off as a new thread.

ChrisA
___
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/WP74PEDSNWIA6VCAKR3LHJRDU3GWUHZJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Eric V. Smith

On 1/21/2020 2:25 PM, Chris Angelico wrote:


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.


reprlib would seem to be the place for this, if it's not already there.

Eric
___
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/FCEIEYV3I7AC42BE5NH3I6NP7X4GBDS5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Ricky Teachey
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  wrote:

> On Tue, Jan 21, 2020 at 1:49 PM Johan Vergeer 
> wrote:
>
>> 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/nameof
>> ).
>> 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?
>
>
> 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.
> ___
> 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/BS4TX33ADL6TQ3HG3CVBVCNO4QHS2TKK/
> 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/VQ2QBT6ECJ2KSM4DS3WIXERAKAI5ZFFH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Chris Angelico
On Wed, Jan 22, 2020 at 5:48 AM Johan Vergeer  wrote:
>
> 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/nameof).
> 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?

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
___
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/AH3FUD4IQW62OXMYAVDEQPXO4QZFVS3U/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: addition of "nameof" operator

2020-01-21 Thread Todd
On Tue, Jan 21, 2020 at 1:49 PM Johan Vergeer 
wrote:

> 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/nameof
> ).
> 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?


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.
___
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/BS4TX33ADL6TQ3HG3CVBVCNO4QHS2TKK/
Code of Conduct: http://python.org/psf/codeofconduct/