2

I am getting myself more into python and finding it hard to understand the concept of interfaces.

The question is more theoretical.

As I understand having an interface for an end user (the non-developer user) is desirable, but why should classes too have interfaces for other objects/classes ( basically other programs/programmers)) to use?? In the example how does using comment1 or comment 2 in class B change the functioning of the program??

class A():
   def __init__(self,a):
      self.a = a
      print self.a
   def seta(self,newa): #setter
      self.a = newa
      print self.a
   def geta(self): #getter
      return self.a


class B(object):
   def __init__(self,oobj,b):
      self.b = b
      self.oobj = oobj
      print self.b
   def addab(self):
      #a = self.oobj.geta() # —> 1. using interface : the getter method 
      #return (self.b +a)
      return (self.b+self.oobj.a) # —> 2.directly accessing the a attribute

Hopefully I have made myself clear..

EDIT: I did check the other thread mentioned as possible duplicate , but even before attempting to understand @property, I am trying to understand the rationale behind not modifying the attributes by themselves within the program, by different objects.

durga
  • 404
  • 6
  • 12
  • Don't write getters and setters in Python. – kindall Mar 11 '15 at 19:55
  • possible duplicate of [Python @property versus getters and setters](http://stackoverflow.com/questions/6618002/python-property-versus-getters-and-setters) – tzaman Mar 11 '15 at 19:55
  • Using getters and setters is discouraged in Python. What makes you think this usage is encouraged? – jwodder Mar 11 '15 at 19:55
  • I am confused as to why we should be using them in the first place? I was reading up w.r.t interfaces from a book chapter and I could not really understand why we use them when the attributes could be changed by themselves? – durga Mar 11 '15 at 20:02
  • 1
    @durga: What book? If a book is telling you to use getters & setters in Python, stop reading it. – jwodder Mar 11 '15 at 20:02
  • may be i understood it wrong , but this is the quote from the book "The key purpose of modeling an object in object-oriented design is to determine what the public interface of that object will be. The interface is the collection of attributes and methods that other objects can use to interact with that object". Book : Python 3 Object Oriented Programming pg:27 – durga Mar 11 '15 at 20:08
  • 1
    possible duplicate of http://stackoverflow.com/questions/2866987/what-is-the-definition-of-interface-in-object-oriented-programming – br3w5 Mar 11 '15 at 20:16
  • i think you are trying to understand interfaces not getters and setters – br3w5 Mar 11 '15 at 20:16
  • I'd advise to stay away from any book titles " Object Oriented Programming". – iced Mar 11 '15 at 20:16
  • "The interface is the collection of attributes and methods that other objects can use to interact with that object", that it is. In Python the convention is: if the attribute or method starts with `_` then you shouldn't touch it, if it does not start with `_` then go ahead and do whatever you want with it. – Antti Haapala -- Слава Україні Mar 11 '15 at 20:25
  • br3w5 - the book does talk about @property in the later chapters . I do understand what interface from the user end, but I am failing to understand in this specific context. -antti - yup I did read somewhere that python doesnot explicitly mention what to be touched and what not to be touched, but again I don't know why such rules exist – durga Mar 11 '15 at 20:28
  • @durga, re your question in your edit: "I am trying to understand the rationale behind not modifying the attributes by themselves" -- see my (long, sorry) answer for one reason, and a few others listed in the bottom note. – jedwards Mar 11 '15 at 20:39
  • @tzaman: I'm unconvinced this is a duplicate of that particular question. Here, OP is clearly unaware of `@property` in the first place. Perhaps there's a different dupe target, but this one isn't it. – Kevin Mar 11 '15 at 20:43

2 Answers2

5

One of the reasons for using setter methods is to validate the input immediately, and not let an invalid value propagate farther into the code. The earlier you can identify an invalid value, the easier it is to troubleshoot.

Consider the following class:

class A():
    def __init__(self, s, pos):
        self.s   = s
        self.pos = pos

    def get_char(self):
        return self.s[self.pos]

Now consider this code:

a = A("Foo", 1)
a.pos = 2 
a.pos = 10              # Raises no error... yet
a.pos = "Foo"           # Raises no error... yet
# ... time passes ...
print(a.get_char())     # Raises an error now, but much later than when an invalid attribute was set

You will be able to set the pos attribute to whatever you want, it's not until you attempt to use the pos attribute in the get_char() method that an error springs up. This can be difficult to troubleshoot.

So one way some languages handle this is to somehow shield these attributes -- maybe by making them "protected" or "private" -- and giving the rest of the code access to them through getters and setters.

This way, code can be added to the setter method to validate the value then.

For example:

class B():
    def __init__(self, s, pos):
        self._s   = s
        self._pos = pos

    def get_pos(self):
        return self._pos

    def set_pos(self, newpos):
        if not 0 < newpos < len(self._s): raise IndexError
        self._pos = newpos

    def get_char(self):
        return self._s[self._pos]

And

b = B("Foo", 1)
b.set_pos(2)            # This is fine
b.set_pos(10)           # This raises an error
b.set_pos("Foo")        # This raises an error
# ... time passes ...
print(b.get_char())

Now, the calls to b.set_pos(10) and b.set_pos("Foo") both will result in an IndexError, allowing you to catch the invalid input immediately.

Enter Python's properties

But Python gives us properties, (and the @property decorator) which do the same thing, but are cooler.

Consider:

class C(object):
    def __init__(self, s, pos):
        self._s   = s
        self._pos = pos

    @property
    def pos(self):
        return self._pos

    @pos.setter
    def pos(self, newpos):
        if not 0 < newpos < len(self._s): raise IndexError
        self._pos = newpos

    def get_char(self):
        return self._s[self._pos]

Class C does exactly the same input validation as Class B.

c = C("Foo", 1)
c.pos = 2               # This is fine
c.pos = 10              # This raises an error
c.pos = "Foo"           # This raises an error
# ... time passes ...
print(c.get_char())

But with properties, Class C also appears exactly like Class A!

The two sections of code that that interact with classes A and C for reference:

a = A("Foo", 1)
a.pos = 2
a.pos = 10
a.pos = "Foo"
print(a.get_char())

c = C("Foo", 1)
c.pos = 2
c.pos = 10
c.pos = "Foo"
print(c.get_char())

It's not uncommon to start with a Class A, then when some sort of input validation is required, end up with a Class C.

So with properties, you get the safety/flexibility of getter/setter methods but without requiring external code to change.

Note: Input validation isn't the only reason for wanting getter/setter methods. They can be helpful if you want to, for example, (conditionally) modify the given value, or change the internal representation without affecting the API.

jedwards
  • 29,432
  • 3
  • 65
  • 92
  • Jedwards : Thank you. I now atleast get a context where these methods are useful. I will try to wrap my head around properties now. – durga Mar 12 '15 at 00:54
1

One of the important purposes of interfaces is to encourage loose coupling, where one class does not rely on the internal implementation of other classes. At the same time it allows us to define a class confident that other developers won't mess around with internal properties in a way that might cause unexpected behavior. It makes things simpler for other developers, by telling them "here is how you are supposed to use this class."

In the real world, the implementation details of classes change, often quite substantially. If other classes are relying on the internal implementation details of the class, then code dependent on that class will start to malfunction when those details change. By defining a public interface, a class promises other classes which depend on it "I will always have these properties and methods available, even if the details of how I execute them may change."

Additionally public interfaces allow you to define intuitive APIs which better fit the domain you are working in. Consider, for example, a program that stores reviews of restaurants. It's much nicer, as a developer, to be able to call restaurant.average_review_score, rather than having to much about with how a restaurant is defined.

For more on this idea, I would strongly reccommend you read Code Complete by Steve McConnell.

That being said, it is quite common in Python to directly access a class's properties without using a getter or setter. This is quite different from the convention in most other OO languages like Java, C++ and C#. In those languages, the language itself includes constructs for differentiating between the public interface and the private implementation. In Python, we rely on convention and politeness, and wherever possible don't go mucking about with members which have been flagged as private using and underscore.

Nick Bailey
  • 3,078
  • 2
  • 11
  • 13
  • Thank you very much. That explanation makes sense.. I will check the book you mentioned. – durga Mar 12 '15 at 00:59