How do I do this without class methods ?
Jacek Generowicz
jmg at ecs.soton.ac.uk
Wed May 2 10:57:30 EDT 2001
Jacek Generowicz <jmg at ecs.soton.ac.uk> writes:
> (Full version performing to spec. below . . .)
>
> -----------------------------------------------------------
>
> class woderwick:
> bwian = [ 'zero', 'one', 'two', 'many' ]
> _wodger_index = 0 # default
> def __getattr__ ( self, name ):
> if name == 'wodger':
> return self.bwian[self._wodger_index]
What should I do if the operation which is to be performed here is
very expensive, and hence should only be performed once and cached for
future use ?
> raise AttributeError, name
> def __init__ ( self ):
> print self.wodger
>
> def welease_bwian( index ):
> woderwick._wodger_index = index
>
> class rodrigo(woderwick):
> bwian = [ 'cero', 'uno', 'dos', 'demasiados' ]
>
> class roderich(woderwick):
> bwian = [ 'gar nichts', 'eins', 'zwei', 'viele' ]
>
> class roderik(roderich): # :-)
> bwian = [ 'geen bal', 'een', 'twee', 'te veel' ]
>
> class rafal(woderwick):
> bwian = [ 'figa z makiem', 'raz', 'dwa', 'kupa' ]
>
> # Defaults work
> w = woderwick() # zero
> r = rodrigo() # cero
>
> # Change number for all present and future instances
> welease_bwian( 1 )
>
> print w.wodger # one
> woderwick() # one
>
> print r.wodger # uno
> rodrigo() # uno
I've invented a different example, which more closely reflects what I
need. Unfortuanately, with all the alternatives and comments, it has
turned out a little longer that I would like . . . sorry.
import math
# (A hierarchy of) objects whose behaviour changes as a function of a
# globally settable parameter
class polygon:
def __init__ ( self, size ):
self.radius = size
# Called once for each parameter setting, used by all instances
# Hence it would seem natural to implement it as a CLASS method
def set_class_cache ( self, N ):
# Imagine that this is an expensive operation, and hence
# should only be called once for a given choice of N
# Consequently, I can't use the trick of using __getattr__ to
# calculate the value each time.
self.__class__.unit_area = N * math.sin( 2 * math.pi / N )
# Called once for each instance, at a particular parameter setting
def set_instance_cache ( self ):
# Imagine that this is expensive too;
# so calculate it only once for each instance
# after the paremeter has been set
self.area = self.radius * self.unit_area
# Called frequently for any particular instance
def use_instance ( self, coefficient ):
# Called many times for each instance
# should use the instance's cached value
return self.area * coefficient
# Would like to invoke like this (this does NOT work)
def set_parameter_ideal ( klass, N ):
klass.set_class_cache( N )
# Horrible but functioning solution 1: dummy instance
def set_parameter_horrible ( klass, N ):
dummy = klass( 1 )
dummy.set_class_cache( N )
# Horrible but functioning solution 2:
# Implement set_class_cache outside the class
# I really hate this `hacking in polymorphism by hand'.
def set_class_cache_polygon( N ):
polygon.unit_area = N * math.sin( 2 * math.pi / N )
# Imagine there is a class hierarchy here, so I would have to have
# def set_class_cache_wallygon( N ):
# def set_class_cache_schmolygon( N ):
# def set_class_cache_PollyGone( N ): # Dead Parrot
# etc. etc. . . .
# Almost elegant but horribly slow solution: getattr
# Slow because unit_area is recalculated repeatedly
# but (almost) never changes
# Inelegant, because this is a daft place to put the calculation of
# unit_area
def ga ( object, name ):
if name == 'unit_area':
return object.N * math.sin( 2 * math.pi / object.N )
# Normally, this would be defined in the class, but it is done like
# this to avoid clashes with the other solutions
polygon.__getattr__ = ga
def set_parameter_getattr( klass, N ):
klass.N = N
# Trivial example of usage
def use_polygons ( coeff ):
# Create some instances
lots_of_instances = map( polygon, range( 1,3 ) )
# Prepare instances for use, by setting the caches
for instance in lots_of_instances:
instance.set_instance_cache()
# Use the instances
for instance in lots_of_instances:
print instance.use_instance( coeff )
print
# Use the various solutions
set_parameter_getattr( polygon, 3 )
use_polygons( 1 )
set_class_cache_polygon( 4 )
use_polygons( 2 )
set_parameter_horrible( polygon, 3 )
use_polygons( 1 )
# Alas, this does not work
set_parameter_ideal( polygon, 3 )
use_polygons( 2 )
Class methods would make this all so simple :-)
Any edifying comments or suggestions ?
Thanks,
Jacek
More information about the Python-list
mailing list