Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Strategies for controling attribute assignment

1 view
Skip to first unread message

Dale Strickland-Clark

unread,
Oct 2, 2001, 8:01:59 AM10/2/01
to
A 'properly' encapsulated business class tends to involve methods and
attributes. However, managing attribute assignment gets very messy
with __setattr__ as you need to devise a scheme to distinguish class
attributes and working instance variables.

Often, externally visible class attributes need to be validated and
instance variables don't. Or they may get stored elsewhere.

What strategies have people come up with to manage this distinction
without bogging the code down in excessive checks.

I would really like a way to distinguish between these two without
having to check dictionaries.

Thanks.
--
Dale Strickland-Clark
Riverhall Systems Ltd

Steve Holden

unread,
Oct 2, 2001, 8:33:53 AM10/2/01
to
"Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk> wrote in message
news:9lajrtcqsojv72nr8...@4ax.com...
Dale:

I'm not quite sure what problem you are trying to solve here. Are you
suggesting that your code will change some class attributes and some
instance attributes to parameterize the operation of all instances for a
particular context. Maybe I need another cup of coffee ...

Well, the coffee was a good idea. Your problem is that when you *use*
__setattr__ you need to know whether you are setting a class or an instance
variable, right? And you want to set class attributes from inside methods?

Perhaps you'd explain what you mean by "proper" encapsulation is a problem
in your particular context. I'm presuming that you are working in a COM
environment, but of course I've been wrong before...

regards
Steve

PS: See recent thread on not hiding your email address from spam!
--
http://www.holdenweb.com/

Dale Strickland-Clark

unread,
Oct 2, 2001, 9:32:35 AM10/2/01
to
"Steve Holden" <sho...@holdenweb.com> wrote:

I thought this might be difficult to convey. This is typical of the
approach I'm currently using:

def __setattr__(self, field, value):
if self._dbTable.has_key(field):
self._dbTable[field].validate(value)
self._fields[field] = value
self._saved = 0
else:
self.__dict__[field] = value

I have to distinguish between assignments to 'public' attributes
(which will go in my database) and instance variables which are used
throughout the class. I need to validate assignments to the database
but just let everything else through.

But it means that EVERY internal assignment to instance attributes
needs to go through this code.

I guess what I'm after is a distinction between private and public
attrbutes.

Does that make it any clearer?

Steve Holden

unread,
Oct 2, 2001, 10:46:34 AM10/2/01
to
"Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk> wrote in message
news:l1gjrtsru6nual0re...@4ax.com...

I think so. For a start it appears to mean that we can forget all about
class attributes ...

I'm not sure why using a dictionary appears so evil to you, given that you
seem to need the dictionary for field validation anyway. Two possible
simplistic alternatives suggest themselves immediately, which might be
enough to loosen your thinking and give you a better solution for your
needs.

1. Use names with a special prefix for the database fields, then you can
just test the attribute name using beginswith() or similar to determine
whether it's a database filed.

2. Have objects store database fields inside another object (such as a
DatabaseTuple), so instead of assigning

object.dbfield = value

you assign

object.db.field = value

This localises the database fields and means you don't need __setattr__ on
the object itself.

Of course there may well be valid reasons why neither of these approaches is
satisfactory. Explain why not, and others might well have better
suggestions.

regards
Steve
--
http://www.holdenweb.com/

Emile van Sebille

unread,
Oct 2, 2001, 10:43:51 AM10/2/01
to
So, what you're trying to do is manipulate two dicts with one interface
_without_ needing to distinguish which dict is intended. It seems to me
that even with a private/public scheme, you'll need to test _something_.
Why not try letting all the internals use a leading underscore and all the
database not, then test on that.

--

Emile van Sebille
em...@fenx.com

---------


"Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk> wrote in message >

Dale Strickland-Clark

unread,
Oct 2, 2001, 12:13:03 PM10/2/01
to
"Steve Holden" <sho...@holdenweb.com> wrote:

>I think so. For a start it appears to mean that we can forget all about
>class attributes ...
>
>I'm not sure why using a dictionary appears so evil to you, given that you
>seem to need the dictionary for field validation anyway. Two possible
>simplistic alternatives suggest themselves immediately, which might be
>enough to loosen your thinking and give you a better solution for your
>needs.
>
>1. Use names with a special prefix for the database fields, then you can
>just test the attribute name using beginswith() or similar to determine
>whether it's a database filed.
>
>2. Have objects store database fields inside another object (such as a
>DatabaseTuple), so instead of assigning
>
> object.dbfield = value
>
>you assign
>
> object.db.field = value
>
>This localises the database fields and means you don't need __setattr__ on
>the object itself.
>
>Of course there may well be valid reasons why neither of these approaches is
>satisfactory. Explain why not, and others might well have better
>suggestions.
>
>regards
> Steve

Steve,

Thanks for sticking with this so far.

The problem isn't with handling the database assignments. It's the
fact that all instance assignments (self.anything) has to go through
the same code. This is such an ugly overhead.

Throughout the class, there are dozens of uses of instance variables
which are forced through this code. I don't want to know about them.

I guess I'd like to explicitly declare which attributes are part of
the public face of the class and which are not.

I assume my approach is as good as any.

Thanks.

Steve Holden

unread,
Oct 2, 2001, 12:27:02 PM10/2/01
to
"Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk> wrote ...
> "Steve Holden" <sho...@holdenweb.com> wrote:
>
[ ... ]

> >1. Use names with a special prefix for the database fields, then you can
> >just test the attribute name using beginswith() or similar to determine
> >whether it's a database filed.
> >
> >2. Have objects store database fields inside another object (such as a
> >DatabaseTuple), so instead of assigning
> >
> > object.dbfield = value
> >
> >you assign
> >
> > object.db.field = value
> >
> >This localises the database fields and means you don't need __setattr__
on
> >the object itself.
> >
[ ... ]

>
> Thanks for sticking with this so far.
>
> The problem isn't with handling the database assignments. It's the
> fact that all instance assignments (self.anything) has to go through
> the same code. This is such an ugly overhead.
>
> Throughout the class, there are dozens of uses of instance variables
> which are forced through this code. I don't want to know about them.
>
> I guess I'd like to explicitly declare which attributes are part of
> the public face of the class and which are not.
>
> I assume my approach is as good as any.
>
Well, the advantage of centralizing the database fields as attributes of a
contained object is that you then only need to monitor bindingd to the
attributes of that object, so the containing object wouldn't need a
__setattr__() implementation. If you can't do that then I guess you're stucj
with something similar to your current approach.

Tim Peters

unread,
Oct 2, 2001, 2:47:05 PM10/2/01
to pytho...@python.org
[Dale Strickland-Clark, weary of __setattr__]
> ...

> I guess I'd like to explicitly declare which attributes are part of
> the public face of the class and which are not.
>
> I assume my approach is as good as any.

Hard to say, unless I get to define "good" <wink>. Another approach is to
use naming conventions.

Python 2.2's "new-style classes" support customized attribute management
without using __get/set attr__ tricks. Example:

class Clipped(object):
def __init__(self, lo, hi):
"The instance's .x attr is constrained to lo <= .x <= hi"
assert lo <= hi
self.lo, self.hi = lo, hi

def _getx(self):
return self._x

def _setx(self, value):
self._x = min(max(value, self.lo), self.hi)

x = property(_getx, _setx, doc="a bounded value")

a = Clipped(1, 3)
for i in range(5):
a.x = i
print "after setting a.x to", i, "its value is", a.x

That prints

after setting a.x to 0 its value is 1
after setting a.x to 1 its value is 1
after setting a.x to 2 its value is 2
after setting a.x to 3 its value is 3
after setting a.x to 4 its value is 3

"property" is a builtin convenience function in 2.2, but you could write
property() yourself in 2.2 (and without using __get/set attr__). See the
2.2 PEPs for details about the new "attribute descriptor" protocol.


David Bolen

unread,
Oct 2, 2001, 4:45:53 PM10/2/01
to
Dale Strickland-Clark <da...@riverhall.NOSPAMco.uk> writes:

> The problem isn't with handling the database assignments. It's the
> fact that all instance assignments (self.anything) has to go through
> the same code. This is such an ugly overhead.
>
> Throughout the class, there are dozens of uses of instance variables
> which are forced through this code. I don't want to know about them.

But I think that's what Steve's suggestion helps you avoid. By
placing all the database assignments that you do need to monitor into
a contained class, it's only that contained class that needs
__setattr__, and thus your normal instance assignments aren't touched.
And that contained class has no instance variables other than those
that are relevant for the database it represents.

> I guess I'd like to explicitly declare which attributes are part of
> the public face of the class and which are not.

The same suggestion can also help with this problem. Call the
instance of the contained database class "public", and then all users
of your class will be accessing database query/assignments with
references such as "object.public.value"

I suppose if you really wanted to (e.g., users of your object just had
to be able to reference object.value), you could invert this. Leave
all instance variables as just for the database, and place all of your
prior private instance variables into a contained object - let's call
it "private". You'd end up using "self.private.xxxx" instead of just
"self.xxx" inside your object.

--
-- David
--
/-----------------------------------------------------------------------\
\ David Bolen \ E-mail: db...@fitlinxx.com /
| FitLinxx, Inc. \ Phone: (203) 708-5192 |
/ 860 Canal Street, Stamford, CT 06902 \ Fax: (203) 316-5150 \
\-----------------------------------------------------------------------/

Dale Strickland-Clark

unread,
Oct 2, 2001, 5:29:06 PM10/2/01
to
David Bolen <db...@fitlinxx.com> wrote:

>
>The same suggestion can also help with this problem. Call the
>instance of the contained database class "public", and then all users
>of your class will be accessing database query/assignments with
>references such as "object.public.value"
>
>I suppose if you really wanted to (e.g., users of your object just had
>to be able to reference object.value), you could invert this. Leave
>all instance variables as just for the database, and place all of your
>prior private instance variables into a contained object - let's call
>it "private". You'd end up using "self.private.xxxx" instead of just
>"self.xxx" inside your object.
>
>--
>-- David

It would address the problem, you're right, but it lacks the clean
external appearance of the traditional approach.

If I have to resort to these type of tricks, I think I'd rather use a
'set' method for all public assignment instead.

Actually, I've found that if I don't define __setattr__ until the end
of __init__ , most the the inefficiencies I've been suffering are
avoided.

This also helps avoid some of the initialisation problems when using
__setattr__.

class wibble:
def __init__(self):
... stuff...
__setattr__ = set

def set(self, attr, value):
... stuff...

Dale Strickland-Clark

unread,
Oct 2, 2001, 5:34:45 PM10/2/01
to

I can't confess to understanding that entirely but it looks
interesting.

There's some interesting new stuff in 2.2 but I missed this. I look it
up.

Tim Peters

unread,
Oct 2, 2001, 8:02:02 PM10/2/01
to pytho...@python.org
[Dale Strickland-Clark, on a 2.2 "property" example]

> I can't confess to understanding that entirely but it looks
> interesting.
>
> There's some interesting new stuff in 2.2 but I missed this. I
> look it up.

This isn't your fault, it's ours: we're still dead busy implementing all
this great stuff, and producing user-friendly documentation is on hold until
it's all there. Guido got a good start on a tutorial, though:

http://www.python.org/2.2/descrintro.html

If you're an "under the covers" type, this is the heart of it: if you're
trying to get an attribute A from a new-style instance I, A is first looked
up in I's class's dict. *If* A is found in the class dict, *and* A's value
V in the class dict has a __get__ attribute, then V.__get__ is called to
handle the attribute access. Similarly if you're trying to set an attribute
A, or delete it, from a new-style instance I, and A is found in the class
dict, and A's value V there has a __set__ attribute, V.__set__ is called to
handle it. Thus setting, getting and/or deleting a specific attribute can
be customized in any way you can write code to express, and each attribute
can do it differently (if it wants to).

On the one hand that's all there is to it, and things like the new builtin
property(), staticmethod() and classmethod() functions merely exploit it in
straightforward ways. Indeed, you could easily enough write those yourself,
and in Python, if you wanted to.

OTOH, kinda like the metaclass hook, the lowest-level __get__/__set__
protocol is so simple that it's mind-twisting at first (which is partly why
we're packaging the property() etc functions for instant out-of-the-box
use).

I don't think it will happen for 2.2, but Guido isn't opposed to adding new
syntax to make whatever prove to be the most popular gimmicks of this nature
more palatable.


0 new messages