Is It Possible To Delete A Method From An Object (not Class) In Python?
Solution 1:
You can't delete a class method from an instance of that class because the instance doesn't have that method. The protocol is: if o
is an instance of class Foo
, and I call o.bar()
, first o
is examined to see if it has a method named bar
. If it doesn't, then Foo
is examined. The methods aren't bound to the instance unless they override its class.
I don't see any good that can come from the road that you're going down here, either.
Solution 2:
This isn't directly answering your question, but I think a better approach to solving this problem would be to not add/remove the member method domagic
on your wiz
object:
What I would do instead is within the domagic
method, add a condition that checks for the relevant state of the wiz
object, and then only perform the rest of the domagic
method for a valid state, otherwise outputting an error message of your choosing.
def domagic():
if (state != desired_state):
print "You cannot do any magic now!"
return
print "Doing some magic"
[some more commands]
Solution 3:
If an object is in a state where calling a given method on that object doesn't make sense, having it disappear from the object's interface seems like the wrong way to handle the problem. More explicit error handling gives you the ability to explain the problem more precisely to your callers, throwing NotEnoughMana instead of presenting them with a method-not-found error.
If you're worried about having a bunch of function prefixes that look like this:
if self.StateNotValid():
raise NotEnoughMana()
...then you could use a decorator on each function. It's shorter, and gives you an easy way to grep for all special-state-requiring functions.
Solution 4:
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
Solution 5:
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',) {}
Post a Comment for "Is It Possible To Delete A Method From An Object (not Class) In Python?"