Getters and Setters

Bernhard Herzog herzog at online.de
Thu Jul 15 06:19:47 EDT 1999


Andrew Dalke <dalke at bioreason.com> writes:

> Neil Schemenauer <nascheme at ucalgary.ca> proposed:
> > # A mixin class to automagicly create getter/setter methods for
> > # class attributes.

> Here's one optimization, don't recreate getter/setter objects.
> How about this:
> 
> class GetterSetter:
>     def __getattr__(self, name):
>         try:
>             if name[:3] == 'get':
>                 x = _Getter(self.__dict__[name[3:]])
>                 self.__dict__[name] = x
>                 return x

It seems to me that this way, the get* method will always return the
same value, the value of the instance variable when the _Getter was
first instantiated, even if the instance variable changed later.

>             elif name[:3] == 'set':
>                 x = _Setter(self, name[3:])
>                 self.__dict__[name] = x
>                 return x

And this one will introduce a circular reference

>         except KeyError:
>             pass
>         raise AttributeError

 
> Since your timing test does so many repeats (esp. when I increase
> n :), that suggests I can take a 1-time cost per attribute, so
> I can use an eval.
> 
> class GetterSetter:
>     def __getattr__(self, name):
>         try:
>             if name[:3] == 'get':
>                 #x = _Getter(self.__dict__[name[3:]])
> 		val = self.__dict__[name[3:]]
> 		x = eval("lambda :x", {"x": val})
>                 self.__dict__[name] = x
>                 return x

This has the same problems as above, i.e. the method always returns the
same value.

>             elif name[:3] == 'set':
>                 x = _Setter(self, name[3:])
>                 self.__dict__[name] = x
>                 return x
>         except KeyError:
>             pass
>         raise AttributeError

> For my final trick, I'll do the same to the Setter:
> import operator
> class GetterSetter:
>     def __getattr__(self, name):
>         try:
>             if name[:3] == 'get':
>                 #x = _Getter(self.__dict__[name[3:]])
> 		val = self.__dict__[name[3:]]
> 		x = eval("lambda :x", {"x": val})
>                 self.__dict__[name] = x
>                 return x
>             elif name[:3] == 'set':
> 		x = eval("lambda val: set(dict, %s, val)" % `name[3:]`,
> 			 {"dict": self.__dict__, "set": operator.setitem})
>                 #x = _Setter(self, name[3:])
>                 self.__dict__[name] = x

And again a circular reference.

>                 return x
>         except KeyError:
>             pass
>         raise AttributeError
> It's only about 10% slower, though for n==10 it's still about
> 8 times slower.  And it has a nasty case of cyclical references
> (since __dict__ caches the lambda functions, which contain
> a reference to __dict__).  I'll leave cleaning that up as an
> exercise to the student :)

Oh. I should have read the entire post before writing my reply :)


-- 
Bernhard Herzog	  | Sketch, a python based drawing program
herzog at online.de  | http://www.online.de/home/sketch/




More information about the Python-list mailing list