Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Python

Re: raising an exception when multiple inheritance involves same baseThank

 

 

Python python RSS feed   Index | Next | Previous | View Threaded


michael.hines at yale

May 25, 2008, 6:37 AM

Post #1 of 5 (193 views)
Permalink
Re: raising an exception when multiple inheritance involves same baseThank

Thanks very much, Arnaud. That is exactly the hint I needed. Since it is
not multiple inheritance per se I prohibit but only multiple inheritance
involving more than one HocObject class, I replaced your len(bases) > 1
test with
<code>
m = False
for b in bases :
if hasattr(b, '__mro__'):
for bb in b.__mro__ :
if bb == MetaHocObject.ho :
if m == True:
raise Exception("Inheritance of multiple HocObject not
allowed")
m = True

</code>
to get

class A(HocObject): pass

class B(object): pass

class C(): pass

class D(C, B, HocObject): pass # ok

class D(C, A, HocObject): pass # fail

When I fold this idea into my code I may even try to eliminate the class
factory aspect of
class Foo(hclass(h.Vector))
in favor of
class Foo(h.Vector)

Thanks again,
Michael


--
http://mail.python.org/mailman/listinfo/python-list


ptmcg at austin

May 25, 2008, 9:32 AM

Post #2 of 5 (172 views)
Permalink
Re: raising an exception when multiple inheritance involves same baseThank [In reply to]

On May 25, 8:37 am, Michael Hines <michael.hi...@yale.edu> wrote:
> Thanks very much, Arnaud. That is exactly the hint I needed. Since it is
> not multiple inheritance per se I prohibit but only multiple inheritance
> involving more than one HocObject class, I replaced your len(bases) > 1
> test with
> <code>
>     m = False
>     for b in bases :
>       if hasattr(b, '__mro__'):
>         for bb in b.__mro__ :
>           if bb == MetaHocObject.ho :
>             if m == True:
>               raise Exception("Inheritance of multiple HocObject not
> allowed")
>             m = True
>
> </code>
> to get
>
> class A(HocObject): pass
>
> class B(object): pass
>
> class C(): pass
>
> class D(C, B, HocObject): pass # ok
>
> class D(C, A, HocObject): pass # fail
>
> When I fold this idea into my code I may even try to eliminate the class
> factory aspect of
> class Foo(hclass(h.Vector))
> in favor of
> class Foo(h.Vector)
>
> Thanks again,
> Michael

Here's a more general version of your testing code, to detect *any*
diamond multiple inheritance (using your sample classes).

-- Paul


for cls in (A,B,C,D):
seen = set()
try:
bases = cls.__bases__
for b in bases:
if hasattr(b,"__mro__"):
for m in b.__mro__:
if m in seen:
raise Exception("diamond multiple
inheritance")
seen.add(m)
except Exception, e:
print cls,"has diamond MI"
else:
print cls,"is ok"
--
http://mail.python.org/mailman/listinfo/python-list


arnodel at googlemail

May 25, 2008, 10:21 AM

Post #3 of 5 (164 views)
Permalink
Re: raising an exception when multiple inheritance involves same baseThank [In reply to]

Sorry I lost the original post.

Paul McGuire <ptmcg [at] austin> writes:

> On May 25, 8:37 am, Michael Hines <michael.hi...@yale.edu> wrote:
>> Thanks very much, Arnaud. That is exactly the hint I needed. Since it is
>> not multiple inheritance per se I prohibit but only multiple inheritance
>> involving more than one HocObject class, I replaced your len(bases) > 1
>> test with
>> <code>
>>     m = False
>>     for b in bases :
>>       if hasattr(b, '__mro__'):
>>         for bb in b.__mro__ :
>>           if bb == MetaHocObject.ho :
>>             if m == True:
>>               raise Exception("Inheritance of multiple HocObject not
>> allowed")
>>             m = True
>>
>> </code>

I think you don't need to look at the bases' mros, just use
issubclass(), e.g. (untested):

if sum(1 for b in bases if issubclass(b, HocObject)) > 1:
raise Exception("Multiple inheritance from HocObject")

>> to get
>>
>> class A(HocObject): pass
>>
>> class B(object): pass
>>
>> class C(): pass
>>
>> class D(C, B, HocObject): pass # ok
>>
>> class D(C, A, HocObject): pass # fail
>>
>> When I fold this idea into my code I may even try to eliminate the class
>> factory aspect of
>> class Foo(hclass(h.Vector))
>> in favor of
>> class Foo(h.Vector)
>>
>> Thanks again,
>> Michael
>
> Here's a more general version of your testing code, to detect *any*
> diamond multiple inheritance (using your sample classes).
>
> -- Paul
>
>
> for cls in (A,B,C,D):
> seen = set()
> try:
> bases = cls.__bases__
> for b in bases:
> if hasattr(b,"__mro__"):
> for m in b.__mro__:
> if m in seen:
> raise Exception("diamond multiple
> inheritance")
> seen.add(m)
> except Exception, e:
> print cls,"has diamond MI"
> else:
> print cls,"is ok"

All new-style classes descend from object, so any new-style class
with at least two bases makes a diamond! For example the first
version of class D above inherits twice from object, so it will be
caught.

OTOH, old-style classes don't have an __mro__, so this will not catch
diamond inheritance of old-style classes. E.g

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass

--
Arnaud
--
http://mail.python.org/mailman/listinfo/python-list


gagsl-py2 at yahoo

May 25, 2008, 10:53 AM

Post #4 of 5 (164 views)
Permalink
Re: raising an exception when multiple inheritance involves same baseThank [In reply to]

En Sun, 25 May 2008 13:32:39 -0300, Paul McGuire <ptmcg [at] austin> escribió:

> Here's a more general version of your testing code, to detect *any*
> diamond multiple inheritance (using your sample classes).
>
> for cls in (A,B,C,D):
> seen = set()
> try:
> bases = cls.__bases__
> for b in bases:
> if hasattr(b,"__mro__"):
> for m in b.__mro__:
> if m in seen:
> raise Exception("diamond multiple
> inheritance")
> seen.add(m)
> except Exception, e:
> print cls,"has diamond MI"
> else:
> print cls,"is ok"

I think you should exclude the `object` class from the test, because all new-style classes inherit from it and *every* case of multiple inheritance forms a diamond.

--
Gabriel Genellina

--
http://mail.python.org/mailman/listinfo/python-list


Scott.Daniels at Acm

May 25, 2008, 1:56 PM

Post #5 of 5 (163 views)
Permalink
Re: raising an exception when multiple inheritance involves same baseThank [In reply to]

Here are some tweaks on both bits of code:

Paul McGuire wrote:
> On May 25, 8:37 am, Michael Hines <michael.hi...@yale.edu> wrote:
...
>> m = False
>> for b in bases :
>> if hasattr(b, '__mro__'):
>> for bb in b.__mro__ :
>> if bb == MetaHocObject.ho :
>> if m == True:
>> raise Exception("Inheritance of multiple HocObject not
>> allowed")
>> m = True
m = []
for b in bases:
if hasattr(b, '__mro__'):
if MetaHocObject.ho in b.__mro__:
m.append(b)
if m:
raise TypeError('Multiple Inheritance of HocObject by %s '
'not allowed.' % ', '.join(b.__name__ for b in m))

Rationale:
(1) "if m == True" is always a flag for trouble.
(2) When you detect a problem and raise an exception, provide
information about what was wrong.
(3) There is no need to report error conditions early. Accumulate
information and complain (if it can be done without much extra
code) exhaustively because a failure case should not be in the
performance-limiting section anyway.

> Here's a more general version of your testing code, to detect *any*
> diamond multiple inheritance (using your sample classes).
>
> for cls in (A,B,C,D):
> seen = set()
> try:
> bases = cls.__bases__
> for b in bases:
> if hasattr(b,"__mro__"):
> for m in b.__mro__:
> if m in seen:
> raise Exception("diamond multiple
> inheritance")
> seen.add(m)
> except Exception, e:
> print cls,"has diamond MI"
> else:
> print cls,"is ok"

Warning: any two "new-style" classes as parents are necessarily involved
in diamond inheritance (because object will be a common superclass).
I'd make sure you produce (or can produce) all common super-classes,
so you can filter the list to what you want. Maybe something like this:
def diamond_points(class_):
seen = dict((b, set([class_])) for b in class_.__bases__)
for b in class_.__bases__:
if hasattr(b, "__mro__"):
for m in b.__mro__:
if b != m:
seen.setdefault(m, set()).add(b)
for subclass, sources in seen.items():
if len(sources) == 1:
seen.pop(subclass)
return seen

Then you can do a test like:
trouble = diamond_points(class_)
if trouble and (len(trouble) > 1 or object not in trouble):
# you know you have a problem
# If you only have forbidden multi-roots, you could
# test if set(trouble) & forbidden_multi_parents: ...
if object in trouble:
trouble.pop(object) # Avoid simply new-style classes
for common_ancestor, progeny in trouble.items():
print common_ancestor.__name__, 'used by:', ' & '.join(
child.__name__ for child in progeny)


--Scott David Daniels
Scott.Daniels [at] Acm
--
http://mail.python.org/mailman/listinfo/python-list

Python python RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.