[Tutor] class questions
Steven D'Aprano
steve at pearwood.info
Sat Jun 26 15:07:17 CEST 2010
On Sat, 26 Jun 2010 10:17:45 pm Payal wrote:
> Hi,
> Some questions about which I am a bit confused.
>
> 1. I know there is a difference between mro of classic and new style
> classes. but I do not get why we need the new mro, the old one is
> easy to predict and understand?
The old MRO (Method Resolution Order) is broken for classes using
multiple inheritance with a diamond shape inheritance diagram. Not a
little bit broken, but horribly, horribly broken.
If you have something like this class hierarchy:
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
(only with actual methods, of course) then inheritance with old-style
classes cannot work correctly in some circumstances. Fortunately this
sort of inheritance diagram:
A
/ \
B C
\ /
D
is rare for old-style classes. But for new-style classes, *all* multiple
inheritance is diamond-shaped, because all classes inherit back to
object at the top of the diagram:
object
/ \
list str
\ /
myclass
So in order to allow people to inherit from built-ins, we had a choice:
(1) Keep the old MRO and a bug which used to be rare would become
common;
(2) Keep the old MRO but prohibit multiple inheritance and mixins (which
would mean breaking a lot of existing code); or
(3) Change the MRO to one which doesn't have the bug.
The Python developers choose 3. Well, actually, that's not quite true:
nobody noticed that the MRO was broken until *after* new-style classes
were added in version 2.2, and so the new MRO was added in version 2.3.
http://www.python.org/download/releases/2.3/mro/
> 2. A friend of mine told me that in C++ abstract classes are classes
> which can not be instatiated. Is she right, do we have them in
> python, if yes can someone give a simple example?
Python doesn't have a special "abstract class" type, but it is easy to
make one with just two lines of boilerplate:
class AbstractThing:
def __init__(self):
# Next two lines are boilerplate.
if type(self) is Abstract:
raise TypeError("abstract class, you must subclass this")
# init code for non-abstract Thing classes goes here
> 3. In http://www.alan-g.me.uk/tutor/index.htm , Alan has given an
> example in "User Defined Exceptions",
>
> >>> class BrokenError(Exception): pass
>
> Even after reading the section a few times over, I fail to get
> utility of such a class. Can someone please explain with better
> example? Alan can you please cleanup that section, maybe make it
> broader and put the stuff about "SystemExit" elsewhere.
The utility of user-defined exceptions is simply to allow your code to
distinguish between *your* exceptions and other exceptions. Different
people have different policies. Some people prefer this:
def func(x):
if x <= 0:
raise ValueError('x must be positive')
return sqrt(x) + x**2
Other people prefer this:
class DomainError(ValueError):
"""Used for mathematics domain errors."""
pass
def func(x):
if x <= 0:
raise DomainError('x must be positive')
return math.sqrt(x) + math.asin(x**2)
Then when you catch an error:
try:
print func(y)
except DomainError:
# only catches my own error
except ValueError:
# catches any other ValueError
But both solutions are equally good. Normally you don't want fifty
different exception classes in a module, nor do you want every
exception to be the same generic class. How finely you divide the error
classes is up to you.
--
Steven D'Aprano
More information about the Tutor
mailing list