I have a class with a few methods, some of which are only valid when the object is in a particular state. I would like to have the methods simply not be bound to the objects
Looks like the way to dir() works by default is:
dir(obj) == sorted(obj.__dict__.keys() + dir(obj.__class__))
(well, removing duplicates anyway)
So an approach would be:
class Wizard(object):
def __init__(self):
self.mana = 0
def __dir__(self):
natdir = set(self.__dict__.keys() + dir(self.__class__))
if self.mana <= 0:
natdir.remove("domagic")
return list(natdir)
def addmana(self):
self.mana += 1
def domagic(self):
if self.mana <= 0:
raise NotEnoughMana()
print "Abracadabra!"
self.mana -= 1
With the behaviour in Py2.6 being:
>>> wiz = Wizard()
>>> [x for x in dir(wiz) if not x.startswith("_")]
['addmana', 'mana']
>>> wiz.addmana()
>>> [x for x in dir(wiz) if not x.startswith("_")]
['addmana', 'domagic', 'mana']
>>> wiz.domagic()
Abracadabra!
>>> [x for x in dir(wiz) if not x.startswith("_")]
['addmana', 'mana']
>>> wiz.domagic()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 13, in domagic
__main__.NotEnoughMana
You can use a hack like that:
>>> class A(object):
... def test(self):
... print 'test'
...
>>> a = A()
>>> def noattr(name):
... raise AttributeError('no attribute %s' % name)
...
>>> a.test = lambda *a, **k: noattr('test')
>>> a.test()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/Users/piranha/<ipython console> in <module>()
/Users/piranha/<ipython console> in <lambda>(*a, **k)
/Users/piranha/<ipython console> in noattr(name)
AttributeError: no attribute test
Of course, this gives you wrong traceback, but exception is the same. ;-)
Another (IMHO - better) way is to override __getattr__
and then put dispatch logic there, then you can use it like that:
>>> class A(object):
... def __getattr__(self, name):
... def inner(*args, **kwargs):
... print args, kwargs
... return inner
...
>>> a = A()
>>> a.test
<function inner at 0x1006c36e0>
>>> a.test('q')
('q',) {}