Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

instance/class methods: having my cake and eating it too

0 views
Skip to first unread message

Donnal Walter

unread,
Aug 29, 2002, 7:28:14 AM8/29/02
to
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?

Thomas Heller

unread,
Aug 29, 2002, 8:51:15 AM8/29/02
to

"Donnal Walter" <don...@donnal.net> wrote in message news:918bc22f.02082...@posting.google.com...

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


Donnal Walter

unread,
Aug 30, 2002, 11:23:05 AM8/30/02
to

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

Thomas Heller

unread,
Aug 30, 2002, 11:38:54 AM8/30/02
to
"Donnal Walter" <don...@donnal.net> wrote in message news:918bc22f.02083...@posting.google.com...
The most useful reading about this stuff I found is Guido's introduction
http://www.python.org/2.2.1/descrintro.html.

Although, unfortunately, still some important stuff is missing,
see the 'Additional Topics' section at the end.

Thomas


0 new messages