osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

newb question about @property


Steve D'Aprano wrote:
> On Tue, 3 Oct 2017 06:51 am, Bill wrote:
>
>> Can you inspire me with a good decorator problem (standard homework
>> exercise-level will be fine)?
>
> Here is a nice even dozen problems for you. Please ask for clarification if any
> are unclear.

Thank you for sharing the problems on decorators!   I just finished 
reading Bruce Eckels' note on decorators (as well as some of the 
comments left by readers), which you shared a link to, and found the 
whole discussion very informative. If I was to point to two details, the 
analogy of decorator's with macros is helpful to bear in mind, as is the 
remark that "@Wrapper(def f..)" reassigns f to the composition. With the 
latter unstated, the matter can cause confusion!   %-)

Bill

>
>
>
> (1) Write a decorator which simply prints a descriptive message and the name of
> the decorated function once, when the function is first decorated.
>
> E.g. if you write:
>
> @decorate
> def spam(x):
>      return x + 1  # for example
>
> print(spam(1))
> print(spam(2))
>
>
> Python should print:
>
> Decorating function spam.
> 2
> 3
>
>
> Note: "spam" must not be hard-coded, it must be taken from the function being
> decorated. (Hint: all functions have their name available as func.__name__.)
>
>
> (2) Modify the decorator from (1) so that calling the wrapped function also
> print a descriptive message such as "Calling function spam". The expected
> output will be:
>
> Decorating function spam.
> Calling function spam.
> 2
> Calling function spam.
> 3
>
>
> (3) Write a decorator that checks that the decorated function's first argument
> is a non-empty string, raising an appropriate exception if it is not, and lets
> through any other arguments unchanged.
>
>
> (4) Same as above, except the first argument is automatically stripped of
> leading and trailing whitespace and forced to uppercase.
>
>
> (5) Write a decorator which injects the argument 10 into the list of arguments
> received by the wrapped function. E.g. if you write:
>
> @inject
> def add(a, b):
>      return a + b
>
> @inject
> def sub(a, b):
>      return a - b
>
> print(add(5), sub(5))
>
> Python should print "15 5". (And *not* "15 -5".)
>
>
> (6) [ADVANCED] Modify the decorator in (5) so that it takes an argument telling
> it what value to inject into the list of arguments:
>
> @inject(99)
> def sub(a, b):
>      return a - b
>
> print(sub(5))
>
> will now print "94".
>
>
> (7) Write a decorator which checks the decorated function's two arguments are
> given smallest first, swapping them around if needed.
>
>
> (8) Write a decorator which prints the name of the wrapped function, its
> arguments, and the time, each time the wrapped function is called.
>
>
> (9) [ADVANCED] Modify the decorator from (8) to take an argument specifying the
> path to a file, and use the logging module to log the details to that file
> instead of printing them.
>
>
> (10) Write a decorator which adds an "cache" attribute initialised to an empty
> dictionary to the decorated function.
>
>
> (11) Write a decorator which wraps a class (not function!), and adds a "help"
> method to the class which prints a message as shown below. For example:
>
> @addhelp
> class Spam:
>      pass
>
> @addhelp
> class Eggs:
>      pass
>
> x = Spam()
> x.help()
> y = Eggs()
> y.help()
>
> will print:
>
> See http://example.com/Spam
> See http://example.com/Eggs
>
> (Hint: classes also have a __name__ attribute.)
>
>
> (12) [ADVANCED] Write a decorator which wraps a class, and applies the decorator
> from (10) above to each non-dunder? method in the class. That is, after:
>
> @addcaches
> class MyClass:
>      def foo(self):
>          pass
>      def bar(self):
>          pass
>
> print(MyClass.foo.cache, MyClass.bar.cache)
>
> should print "{} {}".
>
>
>
> ? Remember that dunder methods are those that start with two leading and
> trailing underscores: "Double UNDERscore" methods.
>
>
> * * *
>
>
> Bruce Eckel has an excellent introduction to Python decorators, from way back
> when they were first introduced in 2008. His introduction is notable because:
>
> - he points out explicitly that Python decorators are not the same as
>    the Decorator design pattern (I thought they were!);
>
> - he recommends using a class as the decorator, and building the extra
>    functionality in object oriented fashion, rather than functional
>    programming fashion (this may give an easier introduction to those
>    who aren't familiar with functional idioms);
>
> - and he correctly predicted that the introduction of the @ syntactic
>    sugar would have a big impact on the way people think about Python
>    code.
>
>
> http://www.artima.com/weblogs/viewpost.jsp?thread=240808
>
> Feel free to read his post before trying the problems I set.
>
>
>