Когда __set_name__ полезно в python?

#python

#python

Вопрос:

Вчера я видел твит от Raymond Hettinger . Он использовал __set_name__ .

Когда я объявляю __set_name__ для своего класса, имя становится именем экземпляра. Владельцем стал Foo , что и ожидалось, но я не мог понять, когда и как это полезно.

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

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

Это печатает

 <__main__.Bar object at 0x7f48f2968820> was named x by <class '__main__.Foo'>
<__main__.Bar object at 0x7f48f2968c70> was named y by <class '__main__.Foo'>
 

Комментарии:

1. Обычно это используется с протоколом дескриптора. Это полезно, потому что часто дескрипторы хотят знать имя переменной, которой они назначены. Ранее вам нужно было бы указать это имя, например x = Bar('x') , например. Это просто удобство для этого.

Ответ №1:

Как @juanpa предоставил краткое объяснение, он используется для определения имени и класса переменной. Один из его вариантов использования — для ведения журнала. Когда вы хотите записать имя переменной. Этот пример был в руководстве по описанию.

 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