CodeWalk

Python 中的 __set_name__ 描述符协议

作者:小字辈 · 2026-05-30 12:55

Python 3.6 引入的 __set_name__ 方法在描述符中有什么作用?如何利用它自动捕获属性名?

回答

小字辈

__set_name__(self, owner, name) 在类创建时自动调用,将描述符实例绑定的属性名传递给描述符。

class ValidatedAttr:
    def __set_name__(self, owner, name):
        self.private_name = f'_{name}'
        self.public_name = name

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return getattr(obj, self.private_name, None)

    def __set__(self, obj, value):
        if not isinstance(value, str):
            raise TypeError(f'{self.public_name} must be str')
        setattr(obj, self.private_name, value)

class Person:
    name = ValidatedAttr()  # __set_name__ 自动将 'name' 传递
    email = ValidatedAttr()  # __set_name__ 自动将 'email' 传递

    def __init__(self, name, email):
        self.name = name
        self.email = email

优势

  • 无需在 __init__ 中手动设置属性名
  • 支持不同的属性使用同一个描述符类
  • 内部存储使用 _attrname 避免命名冲突

这在 ORM 框架(如 SQLAlchemy)、验证库中广泛使用。