Метод __set_name__
Этот вызывается только один раз, когда создаётся дескриптор вызывается впервые (создаётся экземпляр дескриптора x = MyDescriptor()
) и в него передаётся имя атрибута (x
).
class ValidString:
def __set_name__(self, owner_class, propetry_name):
print(f"owner_class: {owner_class}")
print(f"propetry_name: {propetry_name}")
class Person:
my_new_name = ValidString()
1234567
При запуске этого кода, сразу будет запущен __set_name__()
. Сразу на этапе компиляции, даже если не создавать экземпляр класса Person
class ValidString:
def __set_name__(self, owner_class, propetry_name):
self.propetry_name = propetry_name
def __set__(self, instance, value):
if not isinstance(value, str):
raise ValueError(f"{self.propetry_name} must be a String, but {type(value)} was passed")
#key = "_" + self.propetry_name
#setattr(instance, key, value)
# аналогичная запись
instance.__dict__[self.propetry_name] = value
def __get__(self, instance, owner):
if instance is None:
return self
#key = "_" + self.propetry_name
#return getattr(instance, key, None)
# аналогичная запись
instance.__dict__.get(self.propetry_name, None)
class Person:
name = ValidString()
surname = ValidString()
p = Person()
123456789101112131415161718192021222324
Примечательно то, что у дескриптора нет метода __init__
- т.к. есть __set_name__
который делает то, что нужно
p.name = "Oleg"
p.__dict__
{"name": "Oleg"}
1234
[!warning] Особенность записи имен в пространство имен с дескрипторами Значение
name
запишется сразу в локальное пространство имен экземпляра классаp
, а не классаPerson
- это особенность работы дескриптора.
Если проделать подобное с обычным классом - name
запишется в сам класс (если в самом классе существует name
, она будет перезаписана):
>>> class Person:
... name = "Ivan"
...
>>> p = Person()
>>> p.name
'Ivan'
>>> p.__dict__
{}
>>> p.name = "Dima"
>>> p.name
'Dima'
>>> p.__dict__
{'name': 'Dima'}
>>> Person.name
'Ivan'
>>> Person.__dict__
mappingproxy({'__module__': '__main__', 'name': 'Ivan', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None})
1234567891011121314151617
Чтение имени значения и его запись происходит всегда через дескриптор, поэтому, такой проблемы в дескрипторе нет.
Last updated
Was this helpful?