Python: несколько свойств, один установщик / получатель - PullRequest
16 голосов
/ 23 января 2010

Рассмотрим следующие определения классов

class of2010(object):
    def __init__(self):
        self._a = 1
        self._b = 2
        self._c = 3

    def set_a(self,value):
        print('setting a...')
        self._a = value
    def set_b(self,value):
        print('setting b...')
        self._b = value
    def set_c(self,value):
        print('setting c...')
        self._c = value
    a = property(fset=self.set_a)
    b = property(fset=self.set_b)
    c = property(fset=self.set_c)

обратите внимание, что set_[a|b|c]() делает то же самое. Есть ли способ определить:

def set_magic(self,value):
    print('setting <???>...')
    self._??? = value

один раз и используйте его для a, b, c следующим образом

a = property(fset=self.set_magic)
b = property(fset=self.set_magic)
c = property(fset=self.set_magic)

Ответы [ 4 ]

20 голосов
/ 23 января 2010
def attrsetter(attr):
  def set_any(self, value):
    setattr(self, attr, value)
  return set_any

a = property(fset=attrsetter('_a'))
b = property(fset=attrsetter('_b'))
c = property(fset=attrsetter('_c'))
5 голосов
/ 23 января 2010

Я вижу, что ваши сеттеры просто регистрируют сообщение и затем просто присваивают значение - фактически, ваш принятый ответ просто присваивает значение. Используете ли вы этот шаблон, потому что это принятая практика / общепринятая мудрость на каком-то другом языке, возможно, тот, чье имя начинается с «J»? Если это так, то, пожалуйста, узнайте, что подход Pythonic к этому же дизайну намного проще:

class Of2010(object):
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

Нет установщиков ничего не делающих, никаких промежуточных вызовов функций только для присвоения значения. "Что ты сказал? "Публичное воздействие на переменные-члены? !!" Ну, да на самом деле.

Посмотрите на эти классы с точки зрения клиентского кода. Чтобы использовать ваш класс, клиенты создают объект, а затем присваивают свойство «a», используя:

obj = Of2010()
obj.a = 42

Примечательно, что это точно такой же код для 5-линейного класса, который я разместил выше.

Почему J-язык поддерживает более подробный стиль свойств? Сохранять интерфейс класса в случае будущих изменений требований. Если в какой-то момент времени какое-либо другое значение объекта должно измениться вместе с любыми изменениями в a, то вы должны реализовать механизм свойств. К сожалению, J-язык раскрывает природу механизма доступа к атрибутам для клиентского кода, так что введение свойства в какой-то момент в будущем является назойливой задачей рефакторинга, которая потребует перестройки всех клиентов, использующих этот класс и его атрибут "а".

В Python это не так. Доступ к атрибуту «a» объекта определяется во время выполнения в вызывающей стороне. Поскольку прямой доступ и доступ к свойству оба «выглядят» одинаково, ваш класс Python сохраняет этот интерфейс, даже если фактический механизм отличается. Важно то, что он идентичен в том, что касается кода клиента.

Таким образом, в Java каждый вводит это свойство сложности прямо с момента создания этого класса (и фактически, согласно принятой практике, всех классов), на случай, если это может понадобиться некоторым день в будущем. С Python можно начать с реализации простейшей вещи, которая могла бы работать, то есть прямого доступа к простым переменным-элементам, оставляя в будущем сложный подход на время, когда дополнительный материал действительно необходим и имеет ценность. Поскольку этот день может и не наступить, это огромный шаг вперед в получении этой первой рабочей версии вашего кода.

2 голосов
/ 23 января 2010
class...
 def __setattr__(self, name, value):
  print 'setting', name
  self.__dict__[name] = value

Вот и все.

1 голос
/ 23 января 2010

Может быть, вы ищете __setattr__(self, name, value)

Взгляните здесь

...