Skip to content Skip to sidebar Skip to footer

Is It Possible To Delete A Method From An Object (not Class) In Python?

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 when t

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?"