It is a couple of days later, but I managed to create a more expanded proposal.

This proposal is about having a simple and consistent way of getting the name 
of an object.
Whether it is a class, type, function, method or variable or any other object.

# Why?

## Usage in strings

The first situation this could be used is in strings (for example in 
`__repr__`, `__str__` and `print()`)
I've come across too many situations where the developer made a typo (which is 
usually the developer is a hurry or just having a bad day)
or in the case of a refactoring where the developer didn't rename the object in 
the string representation.

To be honest, I am a big fan of IDEs, like PyCharm, which have great 
refactoring tools, but it doesn't refactor strings.

## Usage in comparisons

Another situation is when you want to do a comparison. An example of this would 
be:

```python
def my_factory(class_name: str):
    if class_name == "Foo":
        return Foo()
    if class_name == "Bar":
        return Bar()
```

I know this is a very simple example that can be solved with the example below, 
but it would be nice if we can do the same with methods, functions and 
attributes.

```python
def my_factory(class_name: str):
    if class_name == Foo.__name__:
        return Foo()
    if class_name == Bar.__name__:
        return Bar()
```

## The Zen of Python
 
The Zen of Python has a couple of items that apply to this one in my opinion:
 
Beautiful is better than ugly.
Simple is better than complex.
Sparse is better than dense.
Readability counts.
**There should be one-- and preferably only one --obvious way to do it.**
Although that way may not be obvious at first unless you're Dutch.

# How?

>From the messages in this thread I concluded there is some confusion about 
>what I would like to achieve with this proposal.
In this part I will try to make it more clear what the behavior would be. For 
now I'll stick to the C# naming `nameof()`. 

## Class names

When you want to get the name of a class, you should just use the name. So 
`nameof(Foo)` becomes `"Foo"` and `nameof(type(foo))` also becomes `"Foo"`.
The results are basically the same as `Foo.__name__` and `type(foo).__name__`.

## Function names

When you want to get the name of a function, you would do the same you do with 
a class.

```python
def foo():
    ...

nameof(foo) #Returns 'foo'
```

This is (again) the same as `foo.__name__`

## Attribute names

You should be able to get the name of an attribute. 

```python
class Foo:
    bar: str = "Hello"
    
    def __init__(self):
        self.baz = "World"

    def __str__(self):
        return f"{nameof(self.bar)}: {bar}, {nameof(self.baz): {baz}}"  # 
Returns "bar: Hello, baz: World"

foo = Foo()

nameof(foo)  # Returns "foo"
nameof(foo.bar) # Returns "bar"
```

As Chris Angelico suggested we can already use a special syntax for f-strings 
which is pretty cool, 
but it has the limitation that we have less control over the output.

```python
return f"{self.name=}"   # returns `self.name="something"`
```

## Invalid usage

There are also situations that will return an error.

```python
nameof(1)
nameof("foo")
nameof(["bar", "baz"])
```

## Stuff to think about

There are also situations that I haven't been able to make a decision about and 
I think these should be discussed further down the road.

```python
nameof(None)
nameof(type)
nameof(int)

_foo = Foo()
nameof(_foo) #Should this return "_foo" or "foo"?
...
```

## How should the interpreter handle it?

I think the interpreter should handle it as anything else that is passed to a 
function, 
so when the value passed to the `nameof()` function doesn't exist, an error 
should be thrown.

# How can this be built in the Python language (or a library)

Some people responded this will be very hard to implement because of the way 
Python is built.
To be honest, I don't know nearly enough about the internals of Python to make 
a solid statement on that.

I also don't know how the new f-string syntax `f"{self.name=}"` works under the 
hood, 
but it does give me the impression that implementing this proposal should be 
possible.

# What about `__name__`?

Most of the examples I wrote above can be solved by just using `__name__`, 
which solves most use cases, except for variable and attribute names, 
which cannot be resolved right now because objects don't have names.

So when we want to follow `There should be one-- and preferably only one 
--obvious way to do it.`
it would be better to use `__name__` on an object, but I believe that would 
cause breaking changes.

What I mean is:

```python
class Foo:
    ...

foo = Foo
print(foo.__name__) # Prints "foo"

foo = Foo()
print(foo.__name__) # Throws AttributeError: 'Foo' object has no attribute 
'__name__'
```
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/CIHKBAMUCEY5HE2NSAXLH3SLDR5WIQYW/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to