Re: confusion with decorators
Dave Angel da...@davea.name wrote: The decorator function will execute while *compiling* the class A, and the one in class B is unreferenced. No, the decorator function is called when *executing* the class body of A. Compilation could have happened weeks earlier. It really does make it a lot easier to understand this sort of issue if you remember that 'class' and 'def' are simply executable statements: the body of 'class' executes as part of the class definition whenever normal execution reaches the 'class' statement, the body of 'def' doesn't execute until the function is called (but default arguments are evaluated when the 'def' is executed). In both cases however the code is fully compiled whenever the module is compiled: that could be when the module is imported or if it is __main__ when the script executes, but after the first run of the program all of the modules (nto the script) will have been compiled once and don't compile again until the source changes. -- Duncan Booth http://kupuguy.blogspot.com -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
Jason Swails於 2013年1月31日星期四UTC+8上午8時34分03秒寫道: 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 @_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 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. 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. 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. While this doesn't make the use of decorators completely pointless (the decorators actually do something in each class, it's just different), it does add a bunch of code duplication which I was at one point hopeful to avoid. I'm still stumbling around with decorators a little, but this exercise has made them a lot clearer to me. Thanks! Jason It sounds that you need a decorator mapper to perform the functionality of your designs. -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
On Thu, Jan 31, 2013 at 12:46 AM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: 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. I don't think this is right. fcn is a passed function (at least if it acts as a decorator) that is declared locally in the _protector_decorator scope. Since newfcn is bound in the same scope and fcn is not defined inside newfcn, I'm pretty sure that newfcn will just grab the fcn passed into the decorator. The following code illustrates what I'm trying to say (I think): test.py: #!/usr/bin/env python a = 3 print 'Global namespace:', a def myfunc(a): def nested_func(): print 'nested_func a is:', a, 'id(a) =', id(a) print 'passed a is:', a, 'id(a) = ', id(a) nested_func() myfunc(10) $ python test.py Global namespace: 3 passed a is: 10 id(a) = 6416096 nested_func a is: 10 id(a) = 6416096 Likewise, newfcn will use the function bound to the passed argument to the decorator. This syntax appears to work in my 'real' program. You probably want to add an extra parameter to the newfcn definition: def newfcn(self, fcn, *args, **kwargs): I don't think I want to do that, since fcn will simply become the first argument that I pass to the decorated myfunc(), and if it's not callable I'll get a traceback. 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. Naturally. I tried to contrive the simplest example to demonstrate what I wanted. In retrospect I should've picked something functional instead. 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. Again, my example code is over-simplified. A brief description of my class is a list of 'patch' (diff) files with various attributes. If I want information from any of those files, I instantiate a Patch instance (and cache it for later use if desired) and return any of the information I want from that patch (like when it was created, who created it, what files will be altered in the patch, etc.). But a lot of these patches are stored online, so I wanted a new class (a RemotePatchList) to handle lists of patches in an online repository. I can do many of the things with an online patch that I can with one stored locally, but not everything, hence my desire to squash the methods I don't want to support. I'd imagine a much more sensible approach is to generate a base class that implements all methods common to both and simply raises an exception in those methods that aren't. I agree it doesn't make much sense to inherit from an object that has MORE functionality than you want. However, my desire to use decorators was not to disable methods in one class vs. another. The _protector_decorator (a name borrowed from my actual code), is designed to wrap a function call inside a try/except, to account for specific exceptions I might raise inside. One of my classes deals with local file objects, and the other deals with remote file objects via urllib. Naturally, the latter has other exceptions that can be raised, like HTTPError and the like. So my desire was to override the decorator to handle more types of exceptions, but leave the underlying methods intact without duplicating them. I can do this without decorators easily enough, but I thought the decorator syntax was a bit more elegant and I saw an opportunity to learn more about them. Possibly Java. I took a Java class in high school once ~10 years ago... haven't used it since. :) Truth be told, outside of Python, the languages I can work in are Fortran (and to a much lesser extent), C and C++. import functools I need to support Python 2.4, and the docs suggest this is 2.5+. Too bad, too, since functools appears pretty useful. Thanks for the help! Jason -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
On Fri, Feb 1, 2013 at 12:25 AM, Jason Swails jason.swa...@gmail.com wrote: On Thu, Jan 31, 2013 at 12:46 AM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: 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. I don't think this is right. fcn is a passed function (at least if it acts as a decorator) that is declared locally in the _protector_decorator scope. Since newfcn is bound in the same scope and fcn is not defined inside newfcn, I'm pretty sure that newfcn will just grab the fcn passed into the decorator. Yet it adds a level of indirection that achieves nothing. Why not simply: def _protector_decorator(fcn): return fcn ? I'm not understanding the purpose here. ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
On Thu, Jan 31, 2013 at 10:28 AM, Chris Angelico ros...@gmail.com wrote: Well, that surely isn't going to work, because it always decorates the same function, the global fcn. I don't think this is right. fcn is a passed function (at least if it acts as a decorator) that is declared locally in the _protector_decorator scope. Since newfcn is bound in the same scope and fcn is not defined inside newfcn, I'm pretty sure that newfcn will just grab the fcn passed into the decorator. Yet it adds a level of indirection that achieves nothing. Why not simply: def _protector_decorator(fcn): return fcn ? I'm not understanding the purpose here. Bad example. A better (longer) one that is closer to my true use-case: from somewhere.exceptions import MyTypeError from somewhere.different import AuthorClass, RemoteAuthorClass from urllib2 import HTTPError class A(object): authorclass = AuthorClass def __init__(self, obj_list): Instantiate a list of obj_list objects that may have an author attribute self.things = [] for o in obj_list: if not isinstance(o, self.authorclass): raise MyTypeError('Bad type given to constructor') self.things.append(o) def _protector(fcn): def newfcn(self, *args, **kwargs): try: return fcn(self, *args, **kwargs) # returns a string except AttributeError: return 'Attribute not available.' except IndexError: return 'Not that many AuthorClasses loaded' return newfcn @_protector def author(self, idx): return self.things[idx].author @_protector def description(self, idx): return self.things[idx].description @_protector def hobbies(self, idx): return self.things[idx].hobbies class B(A): authorclass = RemoteAuthorClass def _protector(fcn): def newfcn(self, *args, **kwargs): try: return fcn(self, *args, **kwargs) except AttributeError: return 'Attribute not available' except IndexError: return 'Not that many RemoteAuthorClasses loaded' except HTTPError: return 'Could not connect' return fcn Basically, while RemoteAuthorClass and AuthorClass are related (via inheritance), the RemoteAuthorClass has the potential for HTTPError's now. I could just expand the A class decorator to catch the HTTPError, but since that should not be possible in AuthorClass, I'd rather not risk masking a bug. I'm under no impressions that the above code will decorate A-inherited functions with the B-decorator (I know it won't), but that's the effect I'm trying to achieve... Thanks! Jason -- Jason M. Swails Quantum Theory Project, University of Florida Ph.D. Candidate 352-392-4032 -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
On Thu, Jan 31, 2013 at 11:00 AM, Jason Swails jason.swa...@gmail.comwrote: On Thu, Jan 31, 2013 at 10:28 AM, Chris Angelico ros...@gmail.com wrote: Well, that surely isn't going to work, because it always decorates the same function, the global fcn. I don't think this is right. fcn is a passed function (at least if it acts as a decorator) that is declared locally in the _protector_decorator scope. Since newfcn is bound in the same scope and fcn is not defined inside newfcn, I'm pretty sure that newfcn will just grab the fcn passed into the decorator. Yet it adds a level of indirection that achieves nothing. Why not simply: def _protector_decorator(fcn): return fcn ? I'm not understanding the purpose here. Bad example. A better (longer) one that is closer to my true use-case: from somewhere.exceptions import MyTypeError from somewhere.different import AuthorClass, RemoteAuthorClass from urllib2 import HTTPError class A(object): authorclass = AuthorClass def __init__(self, obj_list): Instantiate a list of obj_list objects that may have an author attribute self.things = [] for o in obj_list: if not isinstance(o, self.authorclass): raise MyTypeError('Bad type given to constructor') self.things.append(o) def _protector(fcn): def newfcn(self, *args, **kwargs): try: return fcn(self, *args, **kwargs) # returns a string except AttributeError: return 'Attribute not available.' except IndexError: return 'Not that many AuthorClasses loaded' return newfcn @_protector def author(self, idx): return self.things[idx].author @_protector def description(self, idx): return self.things[idx].description @_protector def hobbies(self, idx): return self.things[idx].hobbies class B(A): authorclass = RemoteAuthorClass def _protector(fcn): def newfcn(self, *args, **kwargs): try: return fcn(self, *args, **kwargs) except AttributeError: return 'Attribute not available' except IndexError: return 'Not that many RemoteAuthorClasses loaded' except HTTPError: return 'Could not connect' return fcn Basically, while RemoteAuthorClass and AuthorClass are related (via inheritance), the RemoteAuthorClass has the potential for HTTPError's now. I could just expand the A class decorator to catch the HTTPError, but since that should not be possible in AuthorClass, I'd rather not risk masking a bug. I'm under no impressions that the above code will decorate A-inherited functions with the B-decorator (I know it won't), but that's the effect I'm trying to achieve... The approach I'm switching to here is to make the decorators wrappers instead that are passed the functions that need to be called. Basically, wrap at run-time rather than 'compile time' (i.e., when the Python code is 'compiled' into class definitions). That way each child of the main class can simply change the wrapping behavior by implementing the wrapping functions instead of duplicating all of the code. And since this part of the code is not performance-intensive, I don't care about the overhead of extra function calls. It seems to me to be the more appropriate course of action here, since decorators don't seem to naturally lend themselves to what I'm trying to do. --Jason -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
Steven D'Aprano wrote: 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. Good grief, I can't believe I failed to see that fcn was declared as a parameter to _protector_decorator. You probably want to add an extra parameter to the newfcn definition: def newfcn(self, fcn, *args, **kwargs): And that's also rubbish. The right place for the fcn parameter is the decorator function itself, exactly where it already is. Whatever crack I was smoking yesterday, it must have been pretty awful stuff. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
Jason Swails wrote: On Thu, Jan 31, 2013 at 12:46 AM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: Well, that surely isn't going to work, because it always decorates the same function, the global fcn. I don't think this is right. It certainly isn't. Sorry for the noise. [...] Again, my example code is over-simplified. A brief description of my class is a list of 'patch' (diff) files with various attributes. If I want information from any of those files, I instantiate a Patch instance (and cache it for later use if desired) and return any of the information I want from that patch (like when it was created, who created it, what files will be altered in the patch, etc.). But a lot of these patches are stored online, so I wanted a new class (a RemotePatchList) to handle lists of patches in an online repository. I can do many of the things with an online patch that I can with one stored locally, but not everything, hence my desire to squash the methods I don't want to support. Normally, subclasses should extend functionality, not take it away. A fundamental principle of OO design is that anywhere you could sensibly allow an instance, should also be able to use a subclass. So if you have a Patch class, and a RemotePatch subclass, then everything that a Patch can do, a RemotePatch can do too, because RemotePatch instances *are also* instances of Patch. But the rule doesn't go in reverse: you can't necessarily use a Patch instance where you were using a RemotePatch. Subclasses are allowed to do *more*, but they shouldn't do *less*. On the other hand, if you have a Patch class, and a RemotePatchList class, inheritance does not seem to be the right relationship here. A RemotePatchList does not seem to be a kind of Patch, but a kind of list. I'd imagine a much more sensible approach is to generate a base class that implements all methods common to both and simply raises an exception in those methods that aren't. I agree it doesn't make much sense to inherit from an object that has MORE functionality than you want. If a method is not common to both, it doesn't belong in the base class. The base should only include common methods. In fact, I'm usually rather suspicious of base classes that don't ever get used except as a base for subclassing. I'm not saying it's wrong, but it could be excessive abstraction. Abstraction is good, but you can have too much of a good thing. If the base class is not used, consider a flatter hierarchy: class Patch: ... class RemotePatch(Patch): ... rather than: class PatchBase: ... class Patch(PatchBase): ... class RemotePatch(Patch): ... although this is okay: class PatchBase: ... class Patch(PatchBase): ... class RemotePatch(PatchBase): ... However, my desire to use decorators was not to disable methods in one class vs. another. The _protector_decorator (a name borrowed from my actual code), is designed to wrap a function call inside a try/except, to account for specific exceptions I might raise inside. Ah, your example looked like you were trying to implement some sort of access control, where some methods were flagged as protected to prevent subclasses from using them. Hence my quip about Java. What you describe here makes more sense. One of my classes deals with local file objects, and the other deals with remote file objects via urllib. Naturally, the latter has other exceptions that can be raised, like HTTPError and the like. So my desire was to override the decorator to handle more types of exceptions, but leave the underlying methods intact without duplicating them. decorated(3) 4 One way to do that is to keep a list of exceptions to catch: class Patch: catch_these = [SpamException, HamException] def method(self, arg): try: do_this() except self.catch_these: do_that() The subclass can then extend or replace that list: class RemotePatch(Patch): catch_these = Patch.catch_these + [EggsException, CheeseException] import functools I need to support Python 2.4, and the docs suggest this is 2.5+. Too bad, too, since functools appears pretty useful. functools.wraps is pretty simple. You can use this as an equivalent: # `functools.wraps` was added in Python 2.5. def wraps(func_to_wrap): Return a decorator that wraps its argument. This is a reimplementation of functools.wraps() which copies the name, module, docstring and attributes of the base function to the decorated function. wraps() is available in the standard library from Python 2.5. def undecorated(x): ... '''This is a doc string.''' ... return x+1 ... undecorated.__module__ = 'parrot' undecorated.attr = 'something' @wraps(undecorated) ... def decorated(x): ... return undecorated(x) ... decorated(3) 4 decorated.__doc__ 'This is a doc
Re: confusion with decorators
On Thu, Jan 31, 2013 at 6:16 PM, Steven D'Aprano steve+comp.lang.pyt...@pearwood.info wrote: Normally, subclasses should extend functionality, not take it away. A fundamental principle of OO design is that anywhere you could sensibly allow an instance, should also be able to use a subclass. So if you have a Patch class, and a RemotePatch subclass, then everything that a Patch can do, a RemotePatch can do too, because RemotePatch instances *are also* instances of Patch. But the rule doesn't go in reverse: you can't necessarily use a Patch instance where you were using a RemotePatch. Subclasses are allowed to do *more*, but they shouldn't do *less*. On the other hand, if you have a Patch class, and a RemotePatchList class, inheritance does not seem to be the right relationship here. A RemotePatchList does not seem to be a kind of Patch, but a kind of list. I'd imagine a much more sensible approach is to generate a base class that implements all methods common to both and simply raises an exception in those methods that aren't. I agree it doesn't make much sense to inherit from an object that has MORE functionality than you want. If a method is not common to both, it doesn't belong in the base class. The base should only include common methods. Yes, I agree here. The only reason I was considering NOT doing this was because I wanted to control the exception that gets raised rather than let through a simple NameError. The reason, in case you care, is that I like creating my own custom excepthook() which optionally suppresses tracebacks of the base exception class of my program (which can be overridden by a --debug option of some sort). That way I don't worry about returning error codes and the like and my exceptions double as error messages which don't scare users away. Of course, if I didn't raise the exception myself, then I definitely want to know what line that error occurred on so I can fix it (since that typically means it's a bug or error I did not handle gracefully). I suppose I could get the same effect by dumping everything into a main() function somewhere and wrapping that in a try/except where I catch my base class, but I like the flexibility In fact, I'm usually rather suspicious of base classes that don't ever get used except as a base for subclassing. I'm not saying it's wrong, but it could be excessive abstraction. Abstraction is good, but you can have too much of a good thing. If the base class is not used, consider a flatter hierarchy: class Patch: ... class RemotePatch(Patch): ... rather than: class PatchBase: ... class Patch(PatchBase): ... class RemotePatch(Patch): ... although this is okay: class PatchBase: ... class Patch(PatchBase): ... class RemotePatch(PatchBase): ... This last one is what I've settled on. Patch and RemotePatch have common functionality. But RemotePatch can be downloaded and Patch can be parsed through (in my app, if you're going to spend the time to parse through the whole RemotePatch, it just gets downloaded and instantiated as a Patch). So this last form of inheritance made the most sense to me. However, my desire to use decorators was not to disable methods in one class vs. another. The _protector_decorator (a name borrowed from my actual code), is designed to wrap a function call inside a try/except, to account for specific exceptions I might raise inside. Ah, your example looked like you were trying to implement some sort of access control, where some methods were flagged as protected to prevent subclasses from using them. Hence my quip about Java. What you describe here makes more sense. One of my classes deals with local file objects, and the other deals with remote file objects via urllib. Naturally, the latter has other exceptions that can be raised, like HTTPError and the like. So my desire was to override the decorator to handle more types of exceptions, but leave the underlying methods intact without duplicating them. decorated(3) 4 One way to do that is to keep a list of exceptions to catch: class Patch: catch_these = [SpamException, HamException] def method(self, arg): try: do_this() except self.catch_these: do_that() The subclass can then extend or replace that list: class RemotePatch(Patch): catch_these = Patch.catch_these + [EggsException, CheeseException] Ha! I use this technique all the time to avoid code duplication (it's used several times in the program I'm writing). It didn't even occur to me in this context... Thanks for pointing this out! As always, the time you put into responses and helping is appreciated. All the best, Jason -- http://mail.python.org/mailman/listinfo/python-list
confusion with decorators
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 @_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 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. 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. 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. While this doesn't make the use of decorators completely pointless (the decorators actually do something in each class, it's just different), it does add a bunch of code duplication which I was at one point hopeful to avoid. I'm still stumbling around with decorators a little, but this exercise has made them a lot clearer to me. Thanks! Jason -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
On 01/30/2013 07:34 PM, 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 @_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 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. 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. 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. While this doesn't make the use of decorators completely pointless (the decorators actually do something in each class, it's just different), it does add a bunch of code duplication which I was at one point hopeful to avoid. I'm still stumbling around with decorators a little, but this exercise has made them a lot clearer to me. I'm certainly not the expert on decorators; I've only used them for simple things. But I think I can clear up one misconception. The decorator function will execute while *compiling* the class A, and the one in class B is unreferenced. The decorator @_protector_decorator is shorthand for something like mymethod = _protector_decorator(mymethod) So by the time the compiler ends with class A, the mymethod has its final value. (Note, I've not used a decorator that was defined inside a class, so I'm probably missing the appropriate A. or self. or cls. overrides.) But the order of definition is still correct. A decorator executes once, just after a function is completed. -- DaveA -- http://mail.python.org/mailman/listinfo/python-list
Re: confusion with decorators
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
Confusion about decorators
Hi group, I'm a bit confused regarding decorators. Recently started playing with them with Python3 and wanted (as an excercise) to implement a simple type checker first: I know there are lots of them out there, this is actually one of the reasons I chose that particular function (to compare my solution against other, proven solutions). Starting with a blank slate, I did something along the lines of: class _TypeCheckedFunction(): def __init__(self, decoratedfunction): self._decoratedfunction = decoratedfunction def __call__(self, *args, **kwargs): [...] Actual checking def typecheck(wrappedfunction): checkfunction = _TypeCheckedFunction(wrappedfunction) functools.update_wrapper(checkfunction, wrappedfunction) return checkfunction And decorate my methods like @typecheck def setbar(self, bar: str): This works somewhat. The problem is, however, when the method is actually called. This is what happens: 1. The decorator is called upon import of the decorated class. It creates a _TypeCheckedFunction(setbar) object. 2. When setbar is actually called (blubb.setbar(fooobar)), the __call__ method of the previously created _TypeCheckedFunction is invoked. 3. When trying to call self._decoratedfunction from within that object, this fails: self is missing! self._decoratedfunction is only the *function*, not the bound function of the object that contains setbar(). Therefore I cannot proceed here. Solutions that I have seen working usually consist of two functions wrapped in each other, but I do not know why the additional introduction of a class makes everything fail. Can someone please enlighten me? Best regards, Henrik -- http://mail.python.org/mailman/listinfo/python-list
Re: Confusion about decorators
On 12/12/2011 01:27 PM, Henrik Faber wrote: Hi group, I'm a bit confused regarding decorators. Recently started playing with them with Python3 and wanted (as an excercise) to implement a simple type checker first: I know there are lots of them out there, this is actually one of the reasons I chose that particular function (to compare my solution against other, proven solutions). Starting with a blank slate, I did something along the lines of: class _TypeCheckedFunction(): def __init__(self, decoratedfunction): self._decoratedfunction = decoratedfunction def __call__(self, *args, **kwargs): [...] Actual checking def typecheck(wrappedfunction): checkfunction = _TypeCheckedFunction(wrappedfunction) functools.update_wrapper(checkfunction, wrappedfunction) return checkfunction And decorate my methods like @typecheck def setbar(self, bar: str): This works somewhat. The problem is, however, when the method is actually called. This is what happens: 1. The decorator is called upon import of the decorated class. It creates a _TypeCheckedFunction(setbar) object. 2. When setbar is actually called (blubb.setbar(fooobar)), the __call__ method of the previously created _TypeCheckedFunction is invoked. 3. When trying to call self._decoratedfunction from within that object, this fails: self is missing! self._decoratedfunction is only the *function*, not the bound function of the object that contains setbar(). Therefore I cannot proceed here. Solutions that I have seen working usually consist of two functions wrapped in each other, but I do not know why the additional introduction of a class makes everything fail. Can someone please enlighten me? Best regards, Henrik Not sure how that could work in general, what does bar: str should do? Is that a dictionary? Anyway there is already an implementation if you're interested for type checking: http://oakwinter.com/code/typecheck/ You can have a look at how they do it. -- http://mail.python.org/mailman/listinfo/python-list
Re: Confusion about decorators
On 12 December 2011 13:27, Henrik Faber hfa...@invalid.net wrote: Hi group, I'm a bit confused regarding decorators. Recently started playing with them with Python3 and wanted (as an excercise) to implement a simple type checker first: I know there are lots of them out there, this is actually one of the reasons I chose that particular function (to compare my solution against other, proven solutions). Starting with a blank slate, I did something along the lines of: class _TypeCheckedFunction(): def __init__(self, decoratedfunction): self._decoratedfunction = decoratedfunction def __call__(self, *args, **kwargs): [...] Actual checking def typecheck(wrappedfunction): checkfunction = _TypeCheckedFunction(wrappedfunction) functools.update_wrapper(checkfunction, wrappedfunction) return checkfunction And decorate my methods like @typecheck def setbar(self, bar: str): This works somewhat. The problem is, however, when the method is actually called. This is what happens: 1. The decorator is called upon import of the decorated class. It creates a _TypeCheckedFunction(setbar) object. 2. When setbar is actually called (blubb.setbar(fooobar)), the __call__ method of the previously created _TypeCheckedFunction is invoked. 3. When trying to call self._decoratedfunction from within that object, this fails: self is missing! self._decoratedfunction is only the *function*, not the bound function of the object that contains setbar(). Therefore I cannot proceed here. Solutions that I have seen working usually consist of two functions wrapped in each other, but I do not know why the additional introduction of a class makes everything fail. Can someone please enlighten me? You can (need to?) use the descriptor protocol to deal with methods. from functools import partial class _TypeCheckedFunction(): def __init__(self, decoratedfunction): self._decoratedfunction = decoratedfunction def __call__(self, *args, **kwargs): [...] Actual checking def __get__(self, obj, objtype): return partial(self, obj) (Untested) HTH -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list
Re: Confusion about decorators
On 12.12.2011 14:37, Andrea Crotti wrote: On 12/12/2011 01:27 PM, Henrik Faber wrote: Hi group, I'm a bit confused regarding decorators. Recently started playing with them with Python3 and wanted (as an excercise) to implement a simple type checker first: I know there are lots of them out there, this is actually one of the reasons I chose that particular function (to compare my solution against other, proven solutions). Not sure how that could work in general, what does bar: str should do? Is that a dictionary? No. It's PEP 3107 function annotations. Anyway there is already an implementation if you're interested for type checking: http://oakwinter.com/code/typecheck/ *sigh* no, not really -- this is exactly why I wrote I know there are lots of them out there. I've actually seen and run http://code.activestate.com/recipes/577299-method-signature-type-checking-decorator-for-pytho/ However, this doesn't do it for me -- I want to know why my solution fails, not just use some other solution without really understanding it. I really would like to understand what's going on. I'm especially puzzled about the fact that in my solution, __call__ is called with only the method's arguments (i.e. fooobar) in my example instead of two arguments (self, fooobar). Best regards, Henrik -- http://mail.python.org/mailman/listinfo/python-list
Re: Confusion about decorators
On 12.12.2011 14:45, Arnaud Delobelle wrote: Can someone please enlighten me? You can (need to?) use the descriptor protocol to deal with methods. from functools import partial [...] def __get__(self, obj, objtype): return partial(self, obj) Whoa. This is absolutely fantastic, it now works as expected (I get a reference to self). I am very amazed -- I've been programming Python for about 5 years now and have never even come close to something as a descriptor protocol. Python never ceases to amaze me. Do you have any beginners guide how this works? The Pydoc (Data Model) is comprehensive, but I really don't know where to start to look. Still amazed! Best regards, Henrik -- http://mail.python.org/mailman/listinfo/python-list
Re: Confusion about decorators
On 12 December 2011 13:52, Henrik Faber hfa...@invalid.net wrote: On 12.12.2011 14:45, Arnaud Delobelle wrote: Can someone please enlighten me? You can (need to?) use the descriptor protocol to deal with methods. from functools import partial [...] def __get__(self, obj, objtype): return partial(self, obj) Whoa. This is absolutely fantastic, it now works as expected (I get a reference to self). I am very amazed -- I've been programming Python for about 5 years now and have never even come close to something as a descriptor protocol. Python never ceases to amaze me. Do you have any beginners guide how this works? The Pydoc (Data Model) is comprehensive, but I really don't know where to start to look. Well, I've been using Python for 10 years :) The best reference I know is: http://users.rcn.com/python/download/Descriptor.htm -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list
Re: Confusion about decorators
On 12.12.2011 15:01, Arnaud Delobelle wrote: I am very amazed -- I've been programming Python for about 5 years now and have never even come close to something as a descriptor protocol. Python never ceases to amaze me. Do you have any beginners guide how this works? The Pydoc (Data Model) is comprehensive, but I really don't know where to start to look. Well, I've been using Python for 10 years :) The best reference I know is: http://users.rcn.com/python/download/Descriptor.htm Everyone starts out as a Padawan and I am no exception :-) Maybe five years from now I'll also have made my way to be a Python Jedi and also shake the ins and outs of descriptors out of my sleeve :-) But I can only repeat myself: Python is such an exceptional language, the more and more I know about it, the more I fall in love! Fantastic. I wish we had these types of language when I was a kid! Best regards and thanks again, Henrik -- http://mail.python.org/mailman/listinfo/python-list