Here are some tweaks on both bits of code:

Paul McGuire wrote:
On May 25, 8:37 am, Michael Hines <[EMAIL PROTECTED]> 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
[EMAIL PROTECTED]
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to