Постоянные переменные экземпляра? - PullRequest
8 голосов
/ 06 октября 2009

Я использую @property, чтобы гарантировать, что изменения переменных экземпляра объекта обернуты методами, где мне нужно.

Как быть, когда в экземпляре есть переменная, которая логически не должна изменяться? Например, если я создаю класс для Процесса, каждый экземпляр Процесса должен иметь атрибут PID, к которому будет часто обращаться, но его не следует изменять.

Какой самый Pythonic способ справиться с кем-то, пытающимся изменить эту переменную экземпляра?

  • Просто доверьтесь пользователю, чтобы не пытаться изменить что они не должны?

  • Используйте собственность, но поднимите исключение, если переменная экземпляра изменилось?

  • Что-то еще?

Ответы [ 4 ]

8 голосов
/ 06 октября 2009

Добавьте имя переменной с __ и создайте свойство только для чтения, Python позаботится об исключениях, а сама переменная будет защищена от случайного перезаписи.

class foo(object):
    def __init__(self, bar):
        self.__bar = bar

    @property
    def bar(self):
        return self.__bar

f = foo('bar')
f.bar         # => bar
f.bar = 'baz' # AttributeError; would have to use f._foo__bar
3 голосов
/ 06 октября 2009

Просто доверять пользователю не обязательно плохо; если вы просто пишете быструю программу на Python, которая будет использоваться один раз и выброшена, вы вполне можете просто поверить, что пользователь не изменяет поле pid.

ИМХО самый Pythonic способ применения поля только для чтения - это использование свойства, которое вызывает исключение при попытке установить поле.

Итак, ИМХО, у тебя хорошие инстинкты по этому поводу.

1 голос
/ 07 октября 2009

Просто используйте свойство и скрытый атрибут (с префиксом one underscore).

Простые свойства доступны только для чтения!

>>> class Test (object):
...  @property
...  def bar(self):
...   return self._bar
... 
>>> t = Test()
>>> t._bar = 2
>>> t.bar
2
>>> t.bar = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Скрытие с двойным подчеркиванием не используется, чтобы скрыть реализацию, но чтобы убедиться, что вы не сталкиваетесь с атрибутами подкласса; например, рассмотрим миксин, он должен быть очень осторожным!

Если вы просто хотите скрыть атрибут, используйте одно подчеркивание. И, как вы видите, нет никакой дополнительной магии, которую можно добавить - если вы не определили функцию set, ваше свойство доступно только для чтения, как и возвращаемое значение метода.

1 голос
/ 06 октября 2009

Может быть, вы можете переопределить __setattr__? В линейке,

def __setattr__(self, name, value):
    if self.__dict__.has_key(name):
        raise TypeError, 'value is read only'
    self.__dict__[name] = value
...