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
Thank you for this answer. It is *exactly* what I was looking for. I
had previously studied PEP 252 and other documentation related to it,
but somehow I don't think I ever would have come up with this solution
on my own. Now that I have seen your working example, however, I
understand better how descriptors work, and I thank you very much.
Donnal
Although, unfortunately, still some important stuff is missing,
see the 'Additional Topics' section at the end.
Thomas