2013-07-19 2 views
0

У меня есть класс A, который может быть вызван. У меня также есть подкласс A, называемый B, который я хочу сделать не вызываемым. Когда я пытаюсь позвонить, он должен поднять нормальный «не вызываемый» TypeError.Подкласс класса, вызываемого вызовом

class A(): 
    def __call__(self): 
     print "I did it" 

class B(A): 
    def __call__(self): 
     raise TypeError("'B' object is not callable") 

Как вы можете видеть, что мое решение прямо сейчас, чтобы поднять копию нормального TypeError. Это кажется неправильным, поскольку я просто копирую текст стандартного исключения python. Было бы лучше (на мой взгляд), если бы был способ пометить подкласс как не вызываемый, а затем обработать этот атрибут python.

Каков наилучший способ сделать класс B не вызываемым, учитывая, что это подкласс вызываемого класса A?

+0

Хмм. Вы рассмотрели стандарт ['NotImplementedError'] (http://docs.python.org/2/library/exceptions.html#exceptions.NotImplementedError)? – woozyking

+5

Возможно, вы захотите переосмыслить свой дизайн. Если B не реализует метод, который объявляет A, можете ли вы действительно сказать, что B является своего рода A? – Kevin

ответ

0

Вы можете переопределить создание типа с помощью метаклассов Python. Здесь после создания объекта я заменяю родительский метод __call__ другим, выбрасывающим исключение:

>>> class A(object): 
    def __call__(self): 
     print 'Called !' 


>>> class MetaNotCallable(type): 
    @staticmethod 
    def call_ex(*args, **kwargs): 
      raise NotImplementedError() 

    def __new__(mcs, name, bases, dict): 
     obj = super(MetaNotCallable, mcs).__new__(mcs, name, bases, dict) 
     obj.__call__ = MetaNotCallable.call_ex # Change method ! 
     return obj 


>>> class B(A): 
    __metaclass__ = MetaNotCallable 


>>> a = A() 
>>> a() 
Called ! 
>>> b = B() 
>>> b() 

Traceback (most recent call last): 
    File "<pyshell#131>", line 1, in <module> 
    b() 
    File "<pyshell#125>", line 4, in call_ex 
    raise NotImplementedError() 
NotImplementedError 
+0

Зачем нужен метакласс? Намного проще просто определить метод '__call__' в' B', который вызывает исключение. – augurar

+0

Автор просто сделал это, поэтому я хотел предложить что-то еще ... Я согласен, что он может выглядеть переполненным с первого взгляда, но он предоставляет расширенную функциональность Python - и если несколько классов затронуты, вы просто устанавливаете атрибут '__metaclasse__' и вы закончили - не нужно повторять (это зло !!!). – Emmanuel

Смежные вопросы