Name conflict in class hierarchy
Michele Simionato
michele.simionato at gmail.com
Tue May 23 06:27:54 EDT 2006
Jeffrey Barish wrote:
> I believe that the answer to my question is no, but I want to be sure that I
> understand this issue correctly: 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.
I was bitten by the same issue the first time I used Zope :-(
This is my solution, a metaclass that warns you if you try to override
an attribute defined in some ancestor:
class Base(object):
func = 1
class check_if_we_are_overriding_names(type):
def __new__(mcl, name, bases, dic):
for name, val in dic.iteritems():
if name.endswith("__"): continue
if sum(hasattr(base, name) for base in bases):
print "AlreadyDefinedNameWarning:", name
return super(check_if_we_are_overriding_names, mcl).__new__(
mcl, name, bases, dic)
class MyClass(Base):
__metaclass__ = check_if_we_are_overriding_names
func = 2 # you will get a warning at this point
Michele Simionato
More information about the Python-list
mailing list