On Wed, 30 Jan 2013 19:34:03 -0500, Jason Swails wrote: > Hello, > > I was having some trouble understanding decorators and inheritance and > all that. This is what I was trying to do: > > # untested > class A(object): > def _protector_decorator(fcn): > def newfcn(self, *args, **kwargs): > return fcn(self, *args, **kwargs) > return newfcn
Well, that surely isn't going to work, because it always decorates the same function, the global "fcn". You probably want to add an extra parameter to the newfcn definition: def newfcn(self, fcn, *args, **kwargs): Also, I trust you realise that this is a pointless decorator that doesn't do anything useful? It just adds an extra layer of indirection, without adding any functionality. > @_protector_decorator > def my_method(self, *args, **kwargs): > """ do something here """ > > class B(A): > def _protector_decorator(fcn): > def newfcn(self, *args, **kwargs): > raise MyException('I do not want B to be able to access the > protected functions') > return newfcn That's not going to work, because B's _protector_decorator never gets called. True, it overrides A's _protector_decorator, but too late. A has already used it to decorate the methods, and B does not override those methods, so A's version are inherited. But even if it could work, it relies on class B protecting class A from B. All B needs do to overcome the protection is ... *not* define the magic decorator. > The goal of all that was to be able to change the behavior of my_method > inside class B simply by redefining the decorator. Basically, what I > want is B.my_method() to be decorated by B._protector_decorator, but in > the code I'm running it's decorated by A._protector_decorator. Yes. Remember that you don't have a B.my_method, so B merely inherits A.my_method. > I presume this is because once the decorator is applied to my_method in > class A, A.my_method is immediately bound to the new, 'decorated' > function, which is subsequently inherited (and not decorated, > obviously), by B. Correct. > Am I correct here? My workaround was to simply copy the method from > class A to class B, after which B._protector_decorator decorated the > methods in B. That's not a work-around, that's an anti-pattern. Why is B inheriting from A if you don't want it to be able to use A's methods? That's completely crazy, if you don't mind me saying so. If you don't want B to access A's methods, simply don't inherit from A. I really don't understand what you are trying to accomplish here. Possibly Java. http://dirtsimple.org/2004/12/python-is-not-java.html http://dirtsimple.org/2004/12/java-is-not-python-either.html But you can accomplish something close to what you are after like this: import functools def decorate(func): @functools.wraps(func) def inner(self, *args, **kwargs): protector = getattr(self, '_protect', None) if protector is not None: protector() return func(self, *args, **kwargs) return inner class A(object): @decorate def mymethod(self): """Do something useful.""" class B(A): def _protect(self): raise RuntimeError("I'm sorry Dave, I'm afraid I cannot do that.") Try studying that to see how it works, and then try studying it to realise how pointless it is, since it too relies on class B protecting class A from B. -- Steven -- http://mail.python.org/mailman/listinfo/python-list