16

I saw a tweet from Raymond Hettinger yesterday. He used __set_name__.

When I define __set_name__ method for my Class, the name becomes the instance's name. The owner became Foo, which is also expected but I couldn't figure out when and how this is useful.

class Bar:
    def __set_name__(self, owner, name):
        print(f'{self} was named {name} by {owner}')

class Foo:
    x = Bar()
    y = Bar()

That prints

<__main__.Bar object at 0x7f48f2968820> was named x by <class '__main__.Foo'>
<__main__.Bar object at 0x7f48f2968c70> was named y by <class '__main__.Foo'>
2
  • 12
    This is usually used with the descriptor protocol. It is useful because often descriptors want to know the name of the variable they are assigned to. Previously, you would have to provide that name, e.g. x = Bar('x') for example. This is a just a convenience for that. Commented Dec 4, 2020 at 10:40
  • This is used e.g. to infer the target name a cached property's result should be assigned to. Usually it is the same name as the function being wrapped, but not necessarily. Also, this can be used to verify the cached property is assigned to a class variable and not freestanding. Commented Oct 1 at 13:46

2 Answers 2

13

As @juanpa provided a brief explanation, it is used to know the variable's name and class. One of its use cases is for logging. When you want to log the variable's name. This example was in descriptor's HowTo.

import logging

logging.basicConfig(level=logging.INFO)

class LoggedAccess:

    def __set_name__(self, owner, name):
        self.public_name = name
        self.private_name = '_' + name

    def __get__(self, obj, objtype=None):
        value = getattr(obj, self.private_name)
        logging.info('Accessing %r giving %r', self.public_name, value)
        return value

    def __set__(self, obj, value):
        logging.info('Updating %r to %r', self.public_name, value)
        setattr(obj, self.private_name, value)

class Person:

    name = LoggedAccess()                # First descriptor instance
    age = LoggedAccess()                 # Second descriptor instance

    def __init__(self, name, age):
        self.name = name                 # Calls the first descriptor
        self.age = age                   # Calls the second descriptor

    def birthday(self):
        self.age += 1
Sign up to request clarification or add additional context in comments.

Comments

3

Raymond Hettinger uses this construct as a tool for structural pattern matching. See the documentation of his talk at PyIT 2022.

class FuncCall:
    def __init__(self, func):                                                                                                                                                                                            
        self.func = func

    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, obj, objtype=None):
        return self.func(self.name)

class A:
    x = FuncCall(ord)

A.x

FuncCall is a descriptor to convert fc.name to func(name).

1 Comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.