# 试着让一个实例知晓自己的变量名 (September 5, 2023)

我创建了一个 [GitHub Gist](https://gist.github.com/CNSeniorious000/df96593dad6ea6c46dee3e96ce64d823)

---

这段代码定义了一个名为 `AutoNaming` 的类，该类的作用是自动获取并绑定实例的名称。

1. `__new__` 方法：在创建新实例时，首先调用 `__new__` 方法，它创建了一个新的实例，并调用 `_bind_frame` 方法。
2. `_bind_frame` 方法：获取当前的堆栈帧，并将其存储在实例的 `_frame` 属性中。
3. `_name` 方法：这是一个缓存属性，它试图从 `_frame` 属性中找到实例的名称。如果找到，就返回这个名称。
4. `class_name` 属性：返回实例的类名。
5. `fallback_name` 属性：如果无法获取实例的名称，就返回类名作为备选名称。
6. `name` 属性：返回实例的名称，如果 `_name` 属性不存在，就返回 `fallback_name`。
7. `name` 属性的 setter 方法：允许用户手动设置实例的名称，并将 `_frame` 属性设置为 `None`。
8. `name` 属性的 deleter 方法：删除 `_name` 属性。
9. `__repr__` 方法：返回实例的字符串表示形式，包含类名和实例名。
10. `__str__` 方法：返回实例名。

总的来说，这个类的目的是在创建实例时自动获取并绑定实例的名称，同时也支持手动设置和删除实例名。

```python
# copied from `promplate.prompt.utils`

from functools import cached_property
from inspect import currentframe


class AutoNaming:
    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls)
        obj._bind_frame()
        return obj

    def _bind_frame(self) -> None:
        self._frame = currentframe()

    @cached_property
    def _name(self):
        f = self._frame
        if f and f.f_back and (frame := f.f_back.f_back):
            for name, var in frame.f_locals.items():
                if var is self:
                    return name

    @property
    def class_name(self):
        return self.__class__.__name__

    fallback_name = class_name

    @property
    def name(self):
        return self._name or self.fallback_name

    @name.setter
    def name(self, name):
        self._name = name
        self._frame = None

    @name.deleter
    def name(self):
        del self._name

    def __repr__(self):
        if self._name:
            return f"<{self.class_name} {self.name}>"
        else:
            return f"<{self.class_name}>"

    def __str__(self):
        return f"<{self.name}>"
```