Attributes PEP Enhancement
Joe Salmeri
JoeSalmeri at home.com
Thu Aug 3 16:58:25 EDT 2000
I'm coming into this discussion a little late but I have been working on
something similiar to what you have been discussing.
I created the GetSetAttrib class as an attempt to force references to get or
set an attribute to go through a handler.
The handler can do whatever it wants to resolve the request. Currently I am
just gettting/setting an attribute called '_????' in the instances
dictionary but that is not a requirement.
I have been using this module for a week or so and have yet to find a
situation where it caused a problem.
I would appreciate any comments or suggestions you might have regarding this
method of using attribute handlers.
#**************************************************************************
# GetSetAttrib Class
#**************************************************************************
class GetSetAttrib:
def __getattr__(self, name):
if debug: print 'Attempting to GET: %s' % (name)
if (name[0:6] == '__get_') or (name[0:6] == '__set_'):
raise AttributeError, 'Attribute "%s" not found' % (name)
get_method_name = '__get_%s__' % (name)
try:
return getattr(self,get_method_name)()
except AttributeError:
raise AttributeError, 'Read of attribute "%s" failed - no %s
method found' % (name, get_method_name)
def __setattr__(self, name, value):
if debug: print 'Attempting to SET: %s' % (name)
set_method_name = '__set_%s__' % (name)
try:
getattr(self,set_method_name)(value)
except AttributeError:
raise AttributeError, 'Write of attribute "%s" failed - no %s
method found' % (name, set_method_name)
#**************************************************************************
# Module Test
#**************************************************************************
def Test():
class TestGetSetAttrib(GetSetAttrib):
def __init__(self):
self.__dict__['_x'] = 'value of x'
self.__dict__['_y'] = 'value of y'
def __get_x__(self):
return self.__dict__['_x']
def __set_x__(self, value):
self.__dict__['_x'] = value
def __get_y__(self):
return self.__dict__['_y']
print 'Running Test cases\n'
i = TestGetSetAttrib()
if i.x == 'value of x': print 'SUCCESS: GET the value of x'
if i.y == 'value of y': print 'SUCCESS: GET the value of y'
i.x = 'NEW value of x'
if i.x == 'NEW value of x': print 'SUCCESS: SET the value of x'
try:
i.y = 'NEW value of y'
except AttributeError, error_msg:
if str(error_msg) == 'Write attribute "y" failed - no __set_y__
method found':
print 'SUCCESS: EXCEPTION fired when SET of READ-ONLY y value
attempted'
else:
print 'FAILURE: %s' % error_msg
#**************************************************************************
# Module Initialization
#**************************************************************************
if (__name__ == '__main__'): Test()
"Paul Prescod" <paul at prescod.net> wrote in message
news:397BDB62.9BA93128 at prescod.net...
> Okay, the strong preference of people on the list is for separate method
> handlers for __set_XXX__ and __get_XXX___. I propose the following
> algorithm to try and keep performance reasonable (though probably not as
> good as with the single-method proposal).
>
> When Python sees a class like this:
>
> class Foo:
> def __set_XXX__( self ):
> pass
>
> It would add two things to the class's dict.
>
> __set_XXX__ = <unbound method>
> XXX = <attribute handler flag object>
>
> Now let's say you see this code:
>
> Foo().XXX
>
> This will find the attribute handler object. It will discard that object
> immediately and *restart* its search at the beginning, now looking for
> __get_XXX__. In other words, it detects that XXX is a "special
> attribute" because of an entry in the dictionary but it uses full Python
> inheritance rules to find the appropriate method. In essence the
> attribute handler object is *just a flag* not a useful piece of
> information. The flag is important because how else would we know when
> to look for a __get_XXX__ function? When we are looking up attributes
> that do NOT have handlers, the performance should be identical to today.
>
> If you do this:
>
> foo=Foo()
> foo.__dict__["XXX"]=5
>
> ...you will blow away all three attribute handlers for that attribute.
> You can get them back by reassigning the attribute handler flag object
> to foo.XXX.
>
> If there is no getattr defined then it looks for a generic __getattr__
> (as per usual) and otherwise raises AttributeError.
>
> Setattr works like this: First it does a getattr to see if there is an
> attribute handler object. This first getattr can be optimized away for
> objects that have no attribute handlers at all. If there is no attribute
> handler flag for XXX, the code continues as with today's Python.
>
> If there is a handler flag, Python looks for a setter function. If it
> finds one, it calls it. If it can't find it then we have somewhat of a
> problem. We can either just allow the write using traditional Python
> rules or raise an AttributeError. I think that the latter is appropriate
> because remember what the former will do. It will *overwrite your
> handler*. That isn't a good default action. Another possible default
> action is to write to __XXX instead of XXX.
>
> It would be nice if foo.__dict__["XXX"] were "available" for use rather
> than reserved by the mechanism but I don't see how to work that and
> still get decent performance for property gets -- especially property
> gets that are NOT related to the feature. Anyhow, hacking your
> dictionary is ugly. Just use foo.__xxx .
>
> --
> Paul Prescod - Not encumbered by corporate consensus
> New from Computer Associates: "Software that can 'think', sold by
> marketers who choose not to."
>
More information about the Python-list
mailing list