instance/class methods: having my cake and eating it too
Thomas Heller
theller at python.net
Thu Aug 29 08:51:15 EDT 2002
"Donnal Walter" <donnal at donnal.net> wrote in message news:918bc22f.0208290328.30e8b2d1 at posting.google.com...
> To enforce 'encapsulation' of a class attribute, I would like to
> define a class method that sets that class attribute (format):
>
> class Decimal:
>
> format = '%.0f' # default format is for integer printing
>
> def GetFormat(self):
> return self.format
>
> def SeeFormat(self):
> print self.GetFormat()
>
> def SetDigits(cls, digits):
> digits = min(digits, 5)
> cls.format = "%%.%uf" % digits
>
> SetDigits = classmethod(SetDigits)
>
> class Weight(Decimal):
>
> Decimal.SetDigits(3)
>
> >>> x = Weight()
> >>> x.SeeFormat()
> %.3f
>
> But I also want to be able to override this class attribute with an
> instance attribute that is set using an instance method:
>
> def InstanceSetDigits(self, digits):
> digits = min(digits, 5)
> self.format = "%%.%uf" % digits
>
> class MyContainer:
>
> def __init__(self):
> self.wt = Weight()
> self.wt.InstanceSetDigits(2)
>
> >>> y = MyContainer()
> >>> y.wt.SeeFormat()
> %.2f
>
> This works, but having both SetDigits and InstanceSetDigits is
> redundant code and makes for a confusing API. Is there any way I can
> define ONE method that works like a class method when called from the
> base class object and like an instance method when called from an
> instance?
Sure.
Classes deriving from object can completely customize
the binding process by implementing a __get__ method:
class _BoundMethod:
# Helper class.
def __init__(self, func, first):
self.func = func
self.first = first
def __call__(self, *args):
return self.func(self.first, *args)
class unimethod(object):
# universal method: binds to either a class or an instance
def __init__(self, func):
self.func = func
def __get__(self, inst, type=None):
if inst is None:
# bind to the class
return _BoundMethod(self.func, type)
else:
# bind to the instance
return _BoundMethod(self.func, inst)
Then you can do:
class Decimal:
...
def SetDigits(cls_or_inst, ...):
....
SetDigits = unimethod(SetDigits)
-----
Thomas
More information about the Python-list
mailing list