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

前端 未结 8 1747
借酒劲吻你
借酒劲吻你 2020-12-31 13:24

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

相关标签:
8条回答
  • 2020-12-31 14:19

    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
    
    0 讨论(0)
  • 2020-12-31 14:20

    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',) {}
    
    0 讨论(0)
提交回复
热议问题