I'm assuming what you really want to do is not decorate the base class's copies of those methods, but decorate new overriding copies of those methods in the subclass.
If so, that's easy. The methods don't exist in the dictionary passed to the metaclass because they're not defined in the class definition, they're inherited from the bases. Which the metaclass also has access to. So:
def __new__(cls, name, bases, d):
def find_method(m):
for base in bases:
try:
return getattr(base, m)
except AttributeError:
pass
raise AttributeError("No bases have method '{}'".format(m))
for m in d['methodsToDecorate']:
d[m] = myDecorator(find_method(m))
return type(name, bases, d)
If you really do want to reach into the base class and replace its methods, you can of course do that using the same trick. Just return the base along with the found method, so you can setattr
it.
You asked for overriding a method in the base class. But what if the method actually comes from a more distant ancestor? Then this will still work… but it may not work the way you wanted. If you have multiple bases that share a common ancestor, calling getattr
on each direct base will search that common ancestor once per base, but calling getattr
on the new class will only search it once at the end.
As user2357112 points out in a comment, if what you want to override is "whatever would have been called if I didn't override anything", you can do that by constructing the new class first, then modifying it after the fact, by calling getattr
on the result class itself. In 2.x, this does mean you have to deal with unbound methods instead of functions (in 3.x, that's not an issue, because unbound methods just are functions), but the benefits probably outweigh the cost.