Is it possible to remove a method from an object (not a class) in python?

I have a class with several methods, some of which are only valid when the object is in a certain state. I would like methods to simply not be bound to objects when they are not in a suitable state, so I get something like:

>>> wiz=Wizard()
>>> dir(wiz)
['__doc__', '__module__', 'addmana']
>>> wiz.addmana()
>>> dir(wiz)
['__doc__', '__module__', 'addmana', 'domagic']
>>> wiz.domagic()
>>> dir(wiz)
['__doc__', '__module__', 'addmana']
>>> wiz.domagic()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Wizard instance has no attribute 'domagic'

I can see how to add methods (types.MethodType (method, object)), but I see no way to remove a method for only one object:

>>> wiz.domagic
<bound method Wizard.domagic of <__main__.Wizard instance at 0x7f0390d06950>>
>>> del wiz.domagic
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Wizard instance has no attribute 'domagic'

Overriding __dir__ (and getting an InvalidState or NotEnoughMana exception when called instead of AttributeError for the link) might be fine, but I don't see how to accurately simulate the built-in dir () behavior. (Ideally, I would prefer a method that also works in Python 2.5)

Ideas?

+5
8

, dir() :

dir(obj) == sorted(obj.__dict__.keys() + dir(obj.__class__))

(, , )

, :

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

Py2.6:

>>> 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
+3

, . : if o - Foo, o.bar(), o, bar. , Foo. , .

, , .

+10

, , - / - domagic wiz:

domagic, , wiz, domagic , .

def domagic():
    if (state != desired_state):
        print "You cannot do any magic now!"
        return
    print "Doing some magic"
    [some more commands]
+9

, , . , NotEnoughMana, , , .

, :

if self.StateNotValid():
    raise NotEnoughMana()

... . grep , .

+6

:

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

, , - .; -)

(IMHO - ) - __getattr__, , :

>>> 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',) {}
+2

, , / python, .

, :

, , .

, State Design Pattern:

. , .

, :

  • , Wizard. , / , . , , , , , .
  • , . if/elif . , . , , , , . , unit test .
  • , . .
+1

( ), , __init__ , ​​ . : , Wizard, , Wizard domagic(), magic, __init__(), True. - :

class Wizard(object):
    def __init__(self, magic = False):
        if magic:
            def _domagic():
                print "DOING MAGIC!"
            self.domagic = _domagic

def main():
    mage = Wizard(magic = True)
    nomage = Wizard(magic = False)

    mage.domagic()      # prints "DOING MAGIC!"
    nomage.domagic()    # throws an AttributeError

, - , domagic() , , . , , .

+1

Although I agree that this is the wrong decision, my way to “delete” the method would be to overwrite the function with the property that is calling AttributeError. Thus, hasattrit gives the correct result, but it is not so much trouble as use dir.

0
source

All Articles