14

As the title says.

Coming from Java im used to:

private int A;

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

public int getA() {
    return this.A
}

How do I do that (if I need to) in Python. And if one of __setattr__ or __set__ is used for this, what is the other one used for?

Edit: I feel I need to clarify. I know that in Python one doe's not create setters and getters before they are needed.

Lets say I want to do something like this:

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

What is the "pythonic" way to implement this?

evading
  • 3,032
  • 6
  • 37
  • 57

4 Answers4

18

In python, something like this should be implemented using a property (and then only when they do something useful).

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

In this example, it would be better to just do (as pointed out by Edward):

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

since our getter/setter methods don't actually do anything ... However, properties become very useful when the setter/getter actually does something more than just assign/return an attribute's value.

It could also be implemented using __setattr__/__getattr__ (but it shouldn't be implemented this way as it quickly becomes cumbersome if your class has more than 1 property. I would also guess that doing it this way would be slower than using properties):

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)

In terms of what __setattr__ and __getattr__ actually do... __setattr__/__getattr__ are what are called when you do something like:

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

As for __get__ and __set__: previous posts have discussed that quite nicely.

Note that in python there is no such thing as private variables. In general, in a class member is prefixed with an underscore, you shouldn't mess with it (unless you know what you're doing of course). If it's prefixed with 2 underscores, it will invoke name-mangling which makes it harder to access outside the class. This is used to prevent namespace clashes in inheritance (and those variables are generally also not to be messed with).

wjandrea
  • 28,235
  • 9
  • 60
  • 81
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Good illustration of properties, but could be better with an explanation of why you should use a property over setattr/getattr – Greg May 22 '12 at 18:00
  • 2
    @Greg : I think that looking at the above code, if you have more than one property it becomes obvious which one is easier to maintain -- especially if you're doing more than just a simple `setattr`/`getattr` inside your property setters/getters. – mgilson May 22 '12 at 18:02
  • I don't disagree at all, but clarity is rarely a bad thing. +1 – Greg May 22 '12 at 18:05
  • 2
    So if I would like to calculate something when a attribute is changed I should use a property because of clarity. But __setattr__ could (int theory) be used as well. – evading May 22 '12 at 18:25
9

__set__() is used in descriptors when the descriptor is assigned to. __setattr__() is used when binding to an attribute of an object. Unless you're creating a descriptor, you won't use __set__().

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • Thank you for that answer! It is simple but answers refuser's question regarding `__set__` and `__setattr_`. I am guessing that `__get__` and `__set__` could be used in interesting ways to abuse the language. – Noctis Skytower May 22 '12 at 19:58
8

If the getter/setter are really as trivial as that, then you shouldn't even bother with them: just use an instance variable. If you do need a getter/setter that does something interesting, then you should switch to a property, as mgilson described. Note that you can change from an instance variable to a property without anything that uses your code noticing the difference. I.e., start with:

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

And only change to the property-based accessors mgilson described if/when it turns out you need something interesting to happen when you get/set the attribute.

Edward Loper
  • 15,374
  • 7
  • 43
  • 52
  • 2
    + 1 for recommending a simple instance variable. Python is not Java, and getter/setter (properties in Python) are used much less, only when they are actually needed. – rubik May 22 '12 at 18:03
  • @rubik "../only when the are actually needed." That's probably why I wrote "(if I need to)". – evading May 22 '12 at 18:46
5

Assume you've got class Master with an attribute x which is of class Slave and you want some code to be executed when you assign something to x as in some_master.x = foo. Where will this code be located? It can be in the class Master, in which case you use __setattr__. It can be also in the class Slave, so that it has a control on what is being assigned. In this case, you make Slave a descriptor and use __set__.

Examples:

>>> 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

compare to this:

>>> 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

To answer the question which one is more pythonic, I'd say neither. If you need to actually do something, make it a function. Explicit > implicit.

 def update_param(a):
     update_stuff(a)
     and_calculate_some_thing(a)
     self.a = a
georg
  • 211,518
  • 52
  • 313
  • 390
  • So rather than @x.setter\n def x(self, val):\n self.x=y I should update x through a function? That seems cumbersome if all I want to do is update some related value when x is set? – evading May 22 '12 at 18:54
  • @refuser: as always with design questions, it depends on the concrete use case. In general, exposing the object's state is rarely a good idea. – georg May 22 '12 at 19:58