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 -- http://mail.python.org/mailman/listinfo/python-list