Не должно быть ошибки (согласно документам Python 2.7 ) :

class C(object):
    def __init__(self):
        self.d = {}


    def set_key(self, key, val):
        self.d[key] = val


    def get_key(self, key):
        return self.d[key]


c = C()
delattr(c, 'set_key')

Однако:

AttributeError: set_key

Я могу сделать delattr на объекте класса. Могу ли я удалить связанную функцию из экземпляра?

3
sergzach 13 Дек 2016 в 21:02

3 ответа

Лучший ответ

Я не совсем уверен, почему Python (по крайней мере, 2.7) не позволяет таким образом удалять связанные методы.

Тем не менее, вот один из способов смоделировать желаемое поведение:

def delete_method(obj, method_name):
  def stub(*args, **kwargs):
    raise AttributeError("'%s' object has no attribute '%s'" % (
      obj.__class__.__name__, method_name))
  setattr(obj, method_name, stub)

c = C()
delete_method(c, 'set_key')
c.set_key('the_answer', 42)

При запуске это дает

AttributeError: 'C' object has no attribute 'set_key'

Обратите внимание, что этот метод не универсален: например, вы не сможете использовать его для удаления метода из экземпляра класса dict.

1
NPE 13 Дек 2016 в 18:21

Существует также метод, позволяющий скрыть методы-члены (не удаляя их) для передачи ограниченного интерфейса в другое место:

def safe_interface(obj, enabled):
    "Returns an interface object blocking functions which are not in enabled."

    def assert_name(name):
        if name not in enabled:             
            raise KeyError('No attribute %s.' % name)

    class Caller(object):
        def __getattribute__(self, name):
            assert_name(name)
            return getattr(obj, name)


        def __setattr__(self, name, val):
            assert_name(name)
            setattr(obj, name, val)


    c = Caller()

    return c

if __name__ == '__main__':
    class C(object):
        def __init__(self):
            self.d = {}


        def set_key(self, key, val):
            self.d[key] = val


        def get_key(self, key):
            return self.d[key]

    c = C()

    d = safe_interface(c, ['set_key'])

    key = 'c'
    val = 'm'
    d.set_key(key, val)
    print c.get_key(key)
    print d.get_key(key) # error, this method is not allowed
1
sergzach 14 Дек 2016 в 16:00

set_key является атрибутом класса, а не экземпляра. delattr(C, 'set_key') работает как положено.

Если вы хотите, чтобы функция была недоступна только из одного экземпляра, попробуйте c.set_key = None.

4
Nick Matteo 13 Дек 2016 в 18:09