On Wed, Jan 22, 2020 at 5:48 AM Johan Vergeer <johanverg...@gmail.com> 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/

Reply via email to