Подтвердить что ты не робот

В чем разница между __set__ и __setattr__ в Python и когда следует использовать?

Как говорится в названии.

Переход из Java, используемого для:

private int A;

public void setA(int A) {
    this.A = A;
}

public int getA() {
    return this.A
}

Как мне это сделать (если нужно) в Python. И если для этого используется один из __setattr__ или __set__, то какой другой используется для?

Изменить: Я чувствую, что мне нужно уточнить. Я знаю, что в Python один не создает сеттеры и геттеры, прежде чем они понадобятся.

Предположим, что я хочу сделать что-то вроде этого:

public void setA(int A) {
    update_stuff(A);
    and_calculate_some_thing(A);
    this.A = A;
}

Что такое "питонический" способ реализовать это?

4b9b3361

Ответ 1

В Python нечто подобное должно быть реализовано с использованием property (и только тогда, когда они делают что-то полезное).

class Foo(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self,y):
        self._x = y

В этом примере было бы лучше просто сделать (как указал Эдвард):

class Foo(object):
     def __init__(self):
         self.x = None

так как наши методы getter/setter на самом деле ничего не делают... Однако свойства становятся очень полезными, когда setter/getter фактически делает нечто большее, чем просто присваивает/возвращает значение атрибута.

Это также может быть реализовано с использованием __setattr__/__getattr__ (но это не должно быть реализовано таким образом, поскольку это быстро становится громоздким, если у вашего класса более 1 свойства. Я бы также предположил, что делать это таким образом будет медленнее, чем используя свойства):

class Foo(object):
    def __init__(self):
        self._x = None
    def __setattr__(self,attr,obj):
        if(attr == 'x'):
            object.__setattr__(self,'_x',obj)
        else:
            object.__setattr__(self,attr,obj)

    def __getattr__(self,attr):
        if(attr == 'x'):
            return object.__getattr__(self,'_x')
        else:
            return object.__getattr__(self,attr)

С точки зрения того, что на самом деле делают __setattr__ и __getattr__... __setattr__/__getattr__ - это то, что вызывается, когда вы делаете что-то вроде:

myclassinstance = MyClass()
myclassinstance.x = 'foo'  #translates to MyClass.__setattr__(myclassinstance,'x','foo')
bar = myclassinstance.x    #translates to bar=MyClass.__getattr__(myclassinstance,'x')

Что касается __get__ и __set__: предыдущие посты обсуждали это довольно хорошо.

Обратите внимание, что в python нет такой вещи как частные переменные. В общем, в классе с префиксом подчеркивания, вы не должны связываться с ним (если, конечно, вы не знаете, что делаете). Если к нему добавлено 2 знака подчеркивания, он вызовет искажение имен, что затруднит доступ за пределы класса. Это используется для предотвращения конфликтов пространства имен при наследовании (и эти переменные, как правило, также не должны быть испорчены).

Ответ 2

Если геттер/сеттер действительно так же тривиальны, то вы не должны даже беспокоиться о них: просто используйте переменную экземпляра. Если вам нужен геттер/сеттер, который делает что-то интересное, вам следует переключиться на свойство, как описано в описании. Обратите внимание, что вы можете перейти от переменной экземпляра к свойству без всего, что использует ваш код, заметив разницу. I.e., начните с:

class Foo(object):
    def __init__(self):
        self.x = None

И только измените атрибуты на основе свойств mgilson, если/когда вам оказывается, что вам нужно что-то интересное, когда вы получаете/устанавливаете атрибут.

Ответ 3

__set__() используется в дескрипторах, когда назначен дескриптор. __setattr__() используется при привязке к атрибуту объекта. Если вы не создаете дескриптор, вы не будете использовать __set__().

Ответ 4

Предположим, что у вас есть class Master с атрибутом x, который имеет class Slave, и вы хотите, чтобы какой-то код выполнялся, когда вы присваиваете что-то x, как в some_master.x = foo. Где будет находиться этот код? Он может быть в классе Master, и в этом случае вы используете __setattr__. Он также может быть в классе Slave, так что он имеет контроль над тем, что назначается. В этом случае вы делаете Slave a descriptor и используйте __set__.

Примеры:

>>> class Master(object):
...     def __setattr__(self, name, val):
...         print "run code in Master: %s" % val
... 
>>> a = Master()
>>> a.x = 123
run code in Master: 123

сравните с этим:

>>> class Slave(object):
...     def __set__(self, obj, val):
...         print "run code in Slave: %s" % val
... 
>>> class Master2(object):
...     x = Slave()
... 
>>> b = Master2()
>>> b.x = 345
run code in Slave: 345

Чтобы ответить на вопрос, который больше питоничен, я бы тоже не сказал. Если вам действительно нужно сделать, сделайте его функцией. Явный > неявный.

 def update_param(a):
     update_stuff(a)
     and_calculate_some_thing(a)
     self.a = a