Name conflict in class hierarchy

Scott David Daniels scott.daniels at acm.org
Mon May 22 00:21:24 CEST 2006


Jeffrey Barish wrote:
> Suppose that there are two classes defined as follows:
> 
> class A(object):
>     def f1(self):
>         print 'In A.f1, calling func'
>         self.func()
> 
>     def func(self):
>         print 'In A.func'
> 
> class B(A):
>     def func(self):
>         print 'In B.func, calling A.f1'
>         A.f1(self)
> 
> Class A was defined by someone else or it comes from a library, so I have no
> prior information about what is in it.  I subclass A to add some new
> functionality, and I call the new function "func".  The function B.func
> uses A.f1, but unbeknownst to me, A.f1 uses A.func.  Unfortunately, class B
> overrides func, so the call in A.f1 to self.func actually invokes B.func,
> resulting in this case in an infinite loop.  Is there a way from B to
> specify that A should use its own version of func and ignore the version in
> B?  I know that I could rename A.func to avoid the name clash, but since A
> is actually in a library, I will lose that change when I upgrade the
> library.  I could rename B.func, but there is already a bunch of code that
> calls it so I would have to update all the calls.  That seems like the
> correct solution, though.  The other possibility is to use composition
> rather than subclassing:
> 
> class B:
>     def func(self):
>         print 'In B.func, calling A.f1'
>         a = A()
>         a.f1()
> 
> but then B does not inherit other functions of A that I would like to use. 
> It struck me that this must be a common problem in OOP, so I'm wondering
> whether there is a simple solution that I am missing.

If you insist on this (I find silly) version, I'd suggest you want
to use "has-a" rather than "is-a" relationship between B and A

     class A(object):
         def f1(self):
             print 'In A.f1, calling func'
             self.func()

         def func(self):
             print 'In A.func'

      class B(object):
          def __init__(self, *args, **kwargs):
              self._a = A(*args, **kwargs)

          def func(self):
              print 'In B.func, calling A.f1'
              self._a.f1()


But, you could use this (I think ill-advised) technique if you
need a special-case work-around:

class Bb(A):
     def __init__(self, *args, **kwargs):
         super(Bb, self).__init__(*args, **kwargs)
         self._recursed_func = 0

     def f1(self):
         self._recursed_func += 1
         try:
             return super(Bb, self).f1()
         finally:
             self._recursed_func -= 1

    def func(self):
        if self._recursed_func:
            return super(Bb, self).func()
        print 'In B.func, calling A.f1'
        self.f1()


--Scott David Daniels
scott.daniels at acm.org



More information about the Python-list mailing list