Reputation: 20716
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'>
Upvotes: 14
Views: 9370
Reputation: 730
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)
.
Upvotes: 1
Reputation: 2460
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
Upvotes: 12