Accessors in Python (getters and setters)

mystilleef mystilleef at gmail.com
Sat Jul 15 05:55:14 EDT 2006


On State and Behavior:

To understand objects in terms of state and behavior you need to
absolve yourself from implementation details of languages and think at
an abstract level.

Take a button object, for example. It has state and behavior. Possible
states may include, is_active, is_focused, is_mapped, etc. Behavior is
what the button does when it responds to events, (e.g when you click on
it, or drag it, or position a pointer over it.) If you've done any form
of event based programming (GUI/Games/Simulation), this method of
thinking becomes natural.

As you can see, when I'm designing a button object, I don't care what
Python does with is_active. I don't care how it accesses. I don't care
what is_active means to Python. I don't care about Python's __get__
/__set__ special/latent functions or implementation details. is_active
to me and every other developer is a state of the button object. And at
that level that's all that matters. Python can tell me it's just ones
and zeros for all I care.

In very well designed systems, the state of an object should only be
changed by the object. For example, a third party randomly changing
is_active, (which Python lets you do freely and easily) from False to
True may crash your GUI. And I'm not making this up. Things like this
do really happen depending on the whackyness of your toolkit. So
sometimes, it is my duty to protect the state of an object. Especially
if its state cannot afford to be corrupted rendering the system
unstable. And situations like this are found a plenty in event based
programming. Which is programming objects based almost entirely on
state and behavior. As you can see this has nothing to do with Python
vs Java's vs X's implementation of accessors and how using them sucks,
or how they aren't Pythonic. Some domains just require this stuff.

One of the requirements for designing robust object systems is ensuring
the state of objects aren't easily contaminated. That "state" is the
objects data (read: stuff the object needs to do something "reliably").
And this is why many overzealous OO languages do "force" you to use
accessors. It's not because they hate you or aren't aware of the
convenience of having direct access to an object's attributes. It's
just because these languages convenience/robustness ratios are
different.

Thinking in terms of callable vs non-callable is not helpful for me,
because it isn't high level enough. Thinking in terms of state and
behavior is, because it works regardless of programming language or
implementations. This is the reason I like working with Python. I
wanted a language that didn't bore me with it semantics and allowed me
to focus on design. Let me reiterate, I'm not obsessing over language
semantics, I just need practical, not religious, solutions for my
problem domain.

Bruno Desthuilliers wrote:
> mystilleef wrote:
> (snip)
> >
> > Okay, I feel I need to make myself clear. I certainly I'm not blaming
> > Python for my mistakes. And I don't think language X is better than
> > Python or vice-versa. Okay scrap the vice-versa. It was silly of me to
> > name the variable tmp regardless of whatever excuses I have. This also
> > doesn't mean in the future I wouldn't use shitty names for my
> > attributes. :-) I most likely will. But at least now I know how to
> > minimize its impact of such carelessness. I mentioned them above but I
> > repeat it hear again.
> >
> > 1). Make all attributes of a class private/protected .
>
> Please re-read my answer to your previous mention of this and my other
> remarks in this thread (and below in this thread) about the profound
> differences between Python and Java wrt/ object model and attribute
> access semantics.
>
> > 2). If a "non-callable" attribute is going to be used outside a class,
> > think about making it a property
>
> Unless you don't need to.
>
> > and name the property well,
>
> Indeed !-)
>
> > Other than that we are just arguing semantics of language. For example,
> > your view of objects is by categorizing its attributes in callable and
> > non-callable.
>
> And also API/implementation. These are to orthogonal problems - even in
> Java FWIW !-)
>
> > However, my categorization is state(data) and
> > behavior(methods).
>
> If properties are an equivalent of getters/setters, are properties state
> or behaviour ? According to your views, they are behaviour, if I
> understood you. In that case, what's the difference between 'directely'
> (which in fact implies going thru __getattribute__) accessing a public
> "data" attribute and accessing an implementation attribute by the mean
> of a descriptor (property or custom) ?
>
> * before:
>
> # mylib.py
> class Knight(object):
>    def __init__(self, name):
>      self.name = name
>
>    def sayHello(self):
>      print "hello, I'm %s" % self.name
>
> # mymain.py
> from mylib import Knight
> k = Knight("Robin")
> print k.name
> k.sayHello()
> k.name = "Lancelot"
> k.sayHello()
>
> * after
> # mylib.py
> class Knight(object):
>    def __init__(self, name):
>      self.name = name
>
>    @apply
>    def name():
>      def fget(self):
>         return self._xxx.capitalize()
>
>      def fset(self, name):
>         self._xxx = name
>
>    def sayHello(self):
>      print "hello, I'm %s" % self.name
>
> # mymain.py
> from mylib import Knight
> k = Knight("Robin")
> print k.name
> k.sayHello()
> k.name = "Lancelot"
> k.sayHello()
>
>
>
> > Neither ways of thinking about it is wrong.
>
> From the client code (including other methods of the same class) POV, is
> Knight.name behaviour or state ? Please, don't see it as a flame or a
> pissing context or whatever, and try to seriously answer this question.
>
> Thinking in terms of state and behaviour is certainly not wrong in
> itself, but what is state and what is behaviour ? If I pass a callable
> as an argument to another callable, is the first one data or behaviour ?
> If I return a callable from a another callable, is the first callable
> data or behaviour ?  In a Partial application object [1], is the stored
> callable data or behaviour ? Is the class of an object data or
> behaviour? Is it's metaclass data or behaviour ?
>
> [1] http://www.python.org/dev/peps/pep-0309/
>
>
> > It just
> > reflects the way we design classes. When I'm coding I certainly don't
> > care about how Python accesses tmp.
>
> Neither do I. But I have in mind how I can change the way it is accessed.
>
> > What I do care about is how to
> > change tmp without breaking code left, right and center and the
> > facilities Python provides for making my code robust.
>
> cf Simon's answer and mines. But your original problem is not related to
> tmp being callable or not, it's related to how you use to think about
> them, hence name them.
>
> > Most other OO
> > languages provide accessors in addition to keywords for that kind of
> > stuff.
>
> Most OO languages *don't* provide you accessors - they indeed *forces
> you* to write them even for the most trivial cases. What Python (or any
> other language supporting "computed attributes" syntax) gives you is a
> way to avoid writing tedious, boilerplate code. Not more, not less.
>
> > I knew it wasn't Pythonic, but I wanted to know the Pythonic way
> > to do it. So I asked. My query does not automatically suggest Python
> > sucks. Neither those it suggest that Java or other OO languages are
> > better. I asked because I sincerely wanted to know the Pythonic way
> > handling issues like that.
>
> Mark as implementation what is obviously implementation (be it callable
> or not), mark as API what is obviously API (be it callable or not). In
> both cases, there will be simple ways to either expose an implementation
> name or make a non-callable attribute a property. And *always* try to be
> careful about naming, at least (but not restricted to) wrt/ your API.
>
>
>
> --
> bruno desthuilliers
> python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
> p in 'onurb at xiludom.gro'.split('@')])"




More information about the Python-list mailing list