2010-01-23 7 views
13

Рассмотрим следующие определения классаPython: несколько свойств, один сеттер/добытчика

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 = property(fset=self.set_magic) 
b = property(fset=self.set_magic) 
c = property(fset=self.set_magic) 

ответ

20
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')) 
+0

Это свойство (fset = ...), но в противном случае я бы использовал что-то подобное. – olt

+0

@olt: Спасибо, исправлено. –

1

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

Посмотрите here

2
class... 
def __setattr__(self, name, value): 
    print 'setting', name 
    self.__dict__[name] = value 

Вот и все.

+1

Этот совет устарел. Согласно https://docs.python.org/2/reference/datamodel.html#customizing-attribute-access, «для классов нового стиля, а не для доступа к словарю экземпляра,' __setattr__' должен вызывать метод базового класса с одно и то же имя, например, 'object .__ setattr __ (self, name, value)'. " Обратите внимание, что OP использует класс нового стиля. –

5

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

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

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

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

obj = Of2010() 
obj.a = 42 

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

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

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

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

+0

Я хочу, чтобы действие возникало, когда заданы определенные члены (экземпляра) класса. Я хочу, чтобы те же действия выполнялись для этих участников (мой пример: напечатайте имя члена), не дублируя их сеттеры. это причина, по которой мне нужны сеттеры. в противном случае, как вы мудро сказали. я бы не использовал их, поскольку они не нужны в python. – bandana

+0

Если это так же просто, как распечатать имя при каждом вызове, почему бы просто не закодировать это в родительском __init __(), который всегда вызывается каждым экземпляром? –