osdir.com


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

newb question about @property


On Tue, Oct 3, 2017 at 4:41 AM, Steve D'Aprano
<steve+python at pearwood.info> 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.
>
>
>
> (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.

I also suggest:

(13) Modify the decorator from (8) so that the wrapper has the same
name and doc string as the wrapped function. (Hint: use
functools.wraps)