Я столкнулся с этим вопросом с подобной путаницей, и после того, как я ответил сам за себя, было разумно сообщить о моих выводах здесь для процветания.
Как уже указывал ThiefMaster, параметр «владелец» делает возможными конструкции, такие как classproperty
. Иногда вы хотите, чтобы классы имели маскированные маски как атрибуты не-метода, а использование параметра owner
позволяет вам делать это с помощью обычных дескрипторов.
Но это только половина вопроса. Что касается вопроса «только для чтения», вот что я нашел:
Впервые я нашел ответ здесь: http://martyalchin.com/2007/nov/23/python-descriptors-part-1-of-2/. Сначала я этого не понимал, и мне потребовалось около пяти минут, чтобы обвести вокруг себя голову. Что, наконец, убедило меня, придумал пример.
Рассмотрите наиболее распространенный дескриптор: property
. Давайте используем тривиальный примерный класс со счетчиком свойств, который представляет собой число обращений к счету переменных.
class MyClass(object):
def __init__(self):
self._count = 0
@property
def count(self):
tmp = self._count
self._count += 1
return tmp
@count.setter
def setcount(self):
raise AttributeError('read-only attribute')
@count.deleter
def delcount(self):
raise AttributeError('read-only attribute')
Как мы уже установили, параметр функции __get__
owner
означает, что при обращении к атрибуту на уровне класса, функция __get__
перехватывает вызов GetAttr. Как это бывает, код для property
просто returns the property itself при доступе на уровне класса, но он мог бы что угодно (например, вернуть статическое значение).
Теперь представьте, что произойдет, если __set__
и __del__
работают одинаково. Методы __set__
и __del__
будут перехватывать все вызовы setattr
и delattr
на уровне класса, в дополнение к уровню экземпляра.
Как следствие, это означает, что атрибут «count» MyClass
фактически равен немодифицируемым. Если вы привыкли программировать на статических, скомпилированных языках, таких как Java, это не кажется очень интересным, поскольку вы не можете изменять классы в коде приложения. Но на Python вы можете. Классы считаются объектами, и вы можете динамически назначать любые их атрибуты. Например, допустим, что MyClass
является частью стороннего модуля, а MyClass
почти полностью подходит для нашего приложения (предположим, что там есть другой код, кроме кода для count
), за исключением того, что мы хотели, чтобы метод подсчета работал несколько иначе. Вместо этого мы хотим, чтобы он всегда возвращал 10 для каждого отдельного экземпляра. Мы могли бы сделать следующее:
>>> MyClass.count = 10
>>> myinstance = MyClass()
>>> myinstance.count
10
__set__
Если перехвачен вызов setattr(MyClass, 'count')
, то не было бы никакой возможности реально изменить MyClass. Вместо этого код для setcount
перехватит его и ничего не сможет с ним поделать. Единственным решением было бы изменить исходный код MyClass. (Я даже не уверен, что вы можете перезаписать его в подклассе, потому что я думаю, что определение его в подклассе все равно вызовет код setattr
. Но я не уверен, и поскольку мы уже имеем дело с контрфактуальным здесь, я на самом деле у меня нет способа проверить его.)
Теперь вы можете сказать: «Это именно то, что я хочу!» намеренно не хотел, чтобы мой пользователь переназначил атрибуты моего класса! » К этому я могу сказать только то, что вы не хотели использовать наивные дескрипторы, и я бы направил вас к рассуждениям выше. Разрешить переназначение атрибутов класса намного больше соответствует текущим идиомам Python.
Если вы действительно, ДЕЙСТВИТЕЛЬНО хотите, чтобы атрибут класса только для чтения, я не думаю, что мог бы сказать вам, как. Но если есть решение, это, вероятно, связаны с использованием метаклассов и либо создание property
из метакласса или модификации кода Метакласс для SetAttr и delattr. Но это Deep Magic, и далеко не полный объем этого ответа (и мои собственные способности с Python).
Да, я знаю, что такое «владелец», но как мы можем использовать этот «владелец»? Я не вижу смысла существования «владельца». И я не думаю, что ты ответил на мой второй вопрос. – Alcott
Это один, поддержал. Итак, как насчет проблемы ** для чтения **? – Alcott
Я предполагаю, что дескрипторы не предназначены для написания на уровне класса, а только на уровне экземпляра. – ThiefMaster