Author ncoghlan
Recipients Jim.Jewett, Trundle, Yury.Selivanov, benjamin.peterson, cvrebert, daniel.urban, eric.araujo, gcbirzan, gvanrossum, jamesh, ncoghlan, pitrou
Date 2013-10-19.13:54:25
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1382190865.44.0.18203789375.issue12029@psf.upfronthosting.co.za>
In-reply-to
Content
The performance hit is that such a change would potentially make it more expensive to figure out that a raised exception *doesn't* match a given "except" clause, along with the complexity of introducing execution of arbitrary code while still unwinding the stack looking for an exception handler for the original exception.

As Benjamin noted above we already support dynamic exception handling through dynamically bound tuple lookups, so I don't think this feature is needed for the Django used case:

>>> caught_exceptions = ()
>>> def f(to_raise):
...     try:
...         raise to_raise
...     except caught_exceptions:
...         print("Caught the exception")
... 
>>> f(Exception)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f
Exception
>>> caught_exceptions = (Exception,)
>>> f(Exception)
Caught the exception

I know Guido indicated above that he considers the current behaviour a bug, and I even agree that enshrining the two slightly different definitions of "issubclass" is ugly, but the complete lack of use cases without other solutions and the complex implications of unifying them mean that I think it may be worth accepting the additional complexity in the language definition instead.

That means the question in my mind is whether we can make it less surprising/user-hostile by issuing a warning at class definition time.

Since all exceptions are required to inherit from BaseException in order to be permitted in raise statements *or* except clauses, it seems to me that having a check in PyType ready that emits a warning when it detects the use of the virtual subclass machinery should suffice. That is, all of these should emit a warning:

  class BadExceptionABC_1(BaseException, metaclass=abc.ABCMeta): pass
  class BadExceptionABC_2(abc.ABC, BaseException): pass
  class BadExceptionABC_3(BaseException):
      def __instancecheck__(*args): return False
  class BadExceptionABC_4(BaseException):
      def __subclasscheck__(*args): return False

We could even go further and make it a DeprecationWarning intially and upgrade to a full TypeError in a later release (although we obviously can't do that if Guido would prefer to unify the behaviour instead).
History
Date User Action Args
2013-10-19 13:54:25ncoghlansetrecipients: + ncoghlan, gvanrossum, jamesh, pitrou, benjamin.peterson, eric.araujo, Trundle, cvrebert, daniel.urban, Yury.Selivanov, Jim.Jewett, gcbirzan
2013-10-19 13:54:25ncoghlansetmessageid: <1382190865.44.0.18203789375.issue12029@psf.upfronthosting.co.za>
2013-10-19 13:54:25ncoghlanlinkissue12029 messages
2013-10-19 13:54:25ncoghlancreate