Name conflict in class hierarchy
Scott David Daniels
scott.daniels at acm.org
Sun May 21 18:21:24 EDT 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