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
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/
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?
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
em...@fenx.com
---------
"Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk> wrote in message >
>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.
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.
> 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 \
\-----------------------------------------------------------------------/
>
>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...
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.