В Mental Game на YouTube Рэймонда Хеттингера:
class Validator:
def __set_name__(self, owner, name):
self.private_name = f'_{name}'
def __get__(self, obj, objtype=None):
return getattr(obj, self.private_name)
def __set__(self, obj, value):
self.validate(value)
setattr(obj, self.private_name, value)
Доу-Ран Лиу утверждает в Написание дескрипторов в Python 3.6+:
[...] вместо использования встроенных функций getattr и setattr нам нужно напрямую обратиться к объекту dict , потому что встроенные функции также будут перехвачены протоколами дескрипторов и вызовут ошибку RecursionError.
class Validator:
def __set_name__(self, owner, name):
self.name= name
def __get__(self, obj, objtype=None):
return obj.__dict__[self.name]
def __set__(self, obj, value):
self.validate(value)
obj.__dict__[self.name] = value
Но в описании дескрипторов на YouTube говорится:
from weakref import WeakKeyDictionary
class Validator:
def __init__(self):
self.data = WeakKeyDictionary()
def __get__(self, obj, owner):
return self.data[obj]
def __set__(self, obj, value):
self.validate(value)
self.data[obj] = value
Каким будет правильный способ реализации дескрипторов?
1 ответ
Первый пример хорош. Все три являются допустимыми реализациями.
Не уверен, почему второй автор говорит, что вы не можете использовать getattr
таким образом. Да, getattr
вызывает протокол дескриптора, но дескриптор назначается для type(obj).__dict__[name]
, но вы устанавливаете private_name
как f'_{name}'
, чтобы не было бесконечной рекурсии ... Было бы , если бы вы использовали self.private_name = name
в __set_name__
вместо self.private_name = f'_{name}'
, но это не то, что делают первые два ...
РЕДАКТИРОВАТЬ: читая эту ссылку, это то, что делает автор ...
При этом второе решение не неверно .
Что касается третьего решения, я предполагаю, что это альтернатива, которая вообще не загрязняет пространство имен экземпляров, сохраняя отдельное пространство имен - WeakKeyDictionary
. Неплохая идея, но она не более «правильная», чем два других. Обратите внимание, что он действительно предполагает, что хэши класса основаны на идентичности, что не так. Вы можете реализовать __hash__
в классе для хеширования на основе чего-то еще, что нормально, если ваш класс "концептуально" неизменен, например некоторый класс Point(x, y)
, который не предоставляет никаких методов мутатора, и хеширует его на основе значений x
и y
. Таким образом, это сделало бы этот подход немного более ограничительным, но в остальном это умное решение, чтобы не возиться с пространством имен экземпляров.
Я полагаю, что первый из них является наиболее питоническим в том смысле, что он идиоматичен. Но опять же, все три решения являются действительными.
Похожие вопросы
Новые вопросы
python
Python — это мультипарадигмальный многоцелевой язык программирования с динамической типизацией. Он предназначен для быстрого изучения, понимания и использования, а также обеспечивает чистый и унифицированный синтаксис. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Если у вас есть вопросы о версии Python, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas, NumPy) укажите это в тегах.