Re: Python presentations

Discussion in 'Python' started by Jean-Michel Pichavant, Sep 13, 2012.

  1. ----- Original Message -----
    > I have to give a couple of Python presentations in the next weeks,
    > and
    > I'm still thinking what is the best approach.
    >
    > In one presentation for example I will present decorators and context
    > managers, and my biggest doubt is how much I should show and explain
    > in
    > slides and how much in an interactive way (with ipython for example).
    >
    > For my experience if I only see code in slides I tend not to believe
    > that it works somehow, but also only looking at someone typing can be
    > hard to follow and understand what is going on..
    >
    > So maybe I should do first slides and then interactive demo, or the
    > other way around, showing first how everything works and then
    > explaining
    > the code with slides.
    >
    > What do you think work best in general?
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >


    I don't like decorators, I think they're not worth the mental effort. So if I were to intend to your presentation, I'd really like you to start demonstrating how decorators are life savers, or with less emphasis, how they can be worth the effort and make me regret all these years without decorators.

    Some features in python have this WoW! effect, try to trigger it in front of your audience, that should really help them focus on the subject and be interested in your presentation.

    Also try to keep the presentation interactive by asking questions to your audience (unless some of them are already participating), otherwise people will be snoring or texting after 20 minutes.

    I think the key for a presentation is to make people interested in the subject and make them realize they can benefit from what you're presenting. Everyone can then google 'python decorators' for the technical and boring details.

    I must add that I'm not en experienced presenter, so take my advices for what they're worth (hmm not sure about this grammatical construct :-/ )

    JM
     
    Jean-Michel Pichavant, Sep 13, 2012
    #1
    1. Advertising

  2. Jean-Michel Pichavant

    alex23 Guest

    Decorators not worth the effort

    On Sep 14, 3:54 am, Jean-Michel Pichavant <>
    wrote:
    > I don't like decorators, I think they're not worth the mental effort.


    Because passing a function to a function is a huge cognitive burden?
     
    alex23, Sep 14, 2012
    #2
    1. Advertising

  3. Re: Decorators not worth the effort

    On 13Sep2012 18:58, alex23 <> wrote:
    | On Sep 14, 3:54 am, Jean-Michel Pichavant <>
    | wrote:
    | > I don't like decorators, I think they're not worth the mental effort.
    |
    | Because passing a function to a function is a huge cognitive burden?

    It is for me when I'm _writing_ the decorator:) But if I get it right
    and name it well I find it dramaticly _decreases_ the cognitive burden
    of the code using the decorator...
    --
    Cameron Simpson <>

    Observing the first balloon ascent in Paris, [Ben] Franklin heard a scoffer
    ask, "What good is it?" He spoke for a generation of scientists in
    his retort, "What good is a newly born infant?" - John F. Kasson
     
    Cameron Simpson, Sep 14, 2012
    #3
  4. Jean-Michel Pichavant

    alex23 Guest

    Re: Decorators not worth the effort

    On Sep 14, 12:12 pm, Cameron Simpson <> wrote:
    > On 13Sep2012 18:58, alex23 <> wrote:
    > | On Sep 14, 3:54 am, Jean-Michel Pichavant <>| wrote:
    > | > I don't like decorators, I think they're not worth the mental effort.
    > |
    > | Because passing a function to a function is a huge cognitive burden?
    >
    > It is for me when I'm _writing_ the decorator:) But if I get it right
    > and name it well I find it dramaticly _decreases_ the cognitive burden
    > of the code using the decorator...


    Okay, I will concede that point :)
     
    alex23, Sep 14, 2012
    #4
  5. Re: Decorators not worth the effort

    > On Sep 14, 3:54 am, Jean-Michel Pichavant <>
    > wrote:
    >> I don't like decorators, I think they're not worth the mental effort.


    Fine.

    I like them because they can vastly improve reusability and drastically
    reduce redundancies (which I hate). Improved reusability and
    reduced redundancies can make applications more readable, easier
    to maintain and faster to develop.
     
    Dieter Maurer, Sep 14, 2012
    #5
  6. Jean-Michel Pichavant

    Terry Reedy Guest

    Re: Decorators not worth the effort

    On 9/13/2012 10:12 PM, Cameron Simpson wrote:
    > On 13Sep2012 18:58, alex23 <> wrote:
    > | On Sep 14, 3:54 am, Jean-Michel Pichavant <>
    > | wrote:
    > | > I don't like decorators, I think they're not worth the mental effort.
    > |
    > | Because passing a function to a function is a huge cognitive burden?


    For parameterized decorators, there is extra cognitive burden. See below.


    > It is for me when I'm _writing_ the decorator:) But if I get it right
    > and name it well I find it dramaticly _decreases_ the cognitive burden
    > of the code using the decorator...


    For a simple, unparameterized wrapper, the difficulty is entirely in the
    wrapper maker. It must define the final wrapper as a nested function and
    return it*. It is irrelevant whether the wrapper maker is used with
    pre-def decorator syntax or with an explicit post-def call.

    *I am here ignoring the option of a class with __call__ method.

    For a parameterized wrapper, using decorator syntax requires passing the
    parameter(s) first and the function to be wrapped later. This requires
    currying the wrapper maker with double nesting. The nesting order may
    seem inside-out to some. For most people, this is extra work compared to
    writing a wrapper that accepts the function and parameters together and
    only has a single level of nesting.

    In other words

    def make_wrapper(func, param):
    def wrapper(*args, **kwds):
    for i in range(param):
    func(*args, **kwds)
    return wrapper

    def f(x): print(x)
    f = make_wrapper(f, 2)
    f('simple')

    # is simpler, at least for some people, than the following
    # which does essentially the same thing.

    def make_outer(param):
    def make_inner(func):
    def wrapper(*args, **kwds):
    for i in range(param):
    func(*args, **kwds)
    return wrapper
    return make_inner

    @make_outer(2)
    def f(x): print(x)
    f('complex')

    Is the gain of not repeating the wrapped function name twice in the
    post-def wrapping call, and the gain of knowing the function will be
    wrapped before reading the def, worth the pain of currying the wrapper
    maker?

    --
    Terry Jan Reedy
     
    Terry Reedy, Sep 14, 2012
    #6
  7. Jean-Michel Pichavant

    Terry Reedy Guest

    Re: Decorators not worth the effort

    On 9/14/2012 5:28 AM, Jean-Michel Pichavant wrote:
    > Decorators are very popular so I kinda already know that the fault is mine. Now to the reason why I have troubles writing them, I don't know. Every time I did use decorators, I spent way too much time writing it (and debugging it).



    --
    Terry Jan Reedy
     
    Terry Reedy, Sep 14, 2012
    #7
  8. Jean-Michel Pichavant

    Terry Reedy Guest

    Re: Decorators not worth the effort

    On 9/14/2012 4:29 PM, Terry Reedy wrote:
    > On 9/13/2012 10:12 PM, Cameron Simpson wrote:
    >> On 13Sep2012 18:58, alex23 <> wrote:
    >> | On Sep 14, 3:54 am, Jean-Michel Pichavant <>
    >> | wrote:
    >> | > I don't like decorators, I think they're not worth the mental effort.
    >> |
    >> | Because passing a function to a function is a huge cognitive burden?

    >
    > For parameterized decorators, there is extra cognitive burden. See below.
    >
    >
    >> It is for me when I'm _writing_ the decorator:) But if I get it right
    >> and name it well I find it dramaticly _decreases_ the cognitive burden
    >> of the code using the decorator...

    >
    > For a simple, unparameterized wrapper, the difficulty is entirely in the
    > wrapper maker. It must define the final wrapper as a nested function and
    > return it*. It is irrelevant whether the wrapper maker is used with
    > pre-def decorator syntax or with an explicit post-def call.
    >
    > *I am here ignoring the option of a class with __call__ method.
    >
    > For a parameterized wrapper, using decorator syntax requires passing the
    > parameter(s) first and the function to be wrapped later. This requires
    > currying the wrapper maker with double nesting. The nesting order may
    > seem inside-out to some. For most people, this is extra work compared to
    > writing a wrapper that accepts the function and parameters together and
    > only has a single level of nesting.
    >
    > In other words
    >
    > def make_wrapper(func, param):
    > def wrapper(*args, **kwds):
    > for i in range(param):
    > func(*args, **kwds)
    > return wrapper
    >
    > def f(x): print(x)
    > f = make_wrapper(f, 2)
    > f('simple')
    >
    > # is simpler, at least for some people, than the following
    > # which does essentially the same thing.
    >
    > def make_outer(param):
    > def make_inner(func):
    > def wrapper(*args, **kwds):
    > for i in range(param):
    > func(*args, **kwds)
    > return wrapper
    > return make_inner
    >
    > @make_outer(2)
    > def f(x): print(x)
    > f('complex')
    >
    > Is the gain of not repeating the wrapped function name twice in the
    > post-def wrapping call, and the gain of knowing the function will be
    > wrapped before reading the def, worth the pain of currying the wrapper
    > maker?
    >



    --
    Terry Jan Reedy
     
    Terry Reedy, Sep 14, 2012
    #8
  9. Jean-Michel Pichavant

    Terry Reedy Guest

    Re: Decorators not worth the effort

    2nd try, hit send button by mistake before

    On 9/14/2012 5:28 AM, Jean-Michel Pichavant wrote:

    > Decorators are very popular so I kinda already know that the fault is
    > mine. Now to the reason why I have troubles writing them, I don't
    > know. Every time I did use decorators, I spent way too much time
    > writing it (and debugging it).


    You are writing parameterized decorators, which require inverted
    currying of the wrapper maker. Perhaps that is why you have trouble. As
    I showed in response to Cameron, it may be easier to avoid that by using
    a traditional post-def wrapping call instead of decorator syntax.

    --
    Terry Jan Reedy
     
    Terry Reedy, Sep 14, 2012
    #9
  10. Jean-Michel Pichavant

    Ian Kelly Guest

    Re: Decorators not worth the effort

    On Fri, Sep 14, 2012 at 2:29 PM, Terry Reedy <> wrote:
    > For a simple, unparameterized wrapper, the difficulty is entirely in the
    > wrapper maker. It must define the final wrapper as a nested function and
    > return it*. It is irrelevant whether the wrapper maker is used with pre-def
    > decorator syntax or with an explicit post-def call.
    >
    > *I am here ignoring the option of a class with __call__ method.
    >
    > For a parameterized wrapper, using decorator syntax requires passing the
    > parameter(s) first and the function to be wrapped later. This requires
    > currying the wrapper maker with double nesting. The nesting order may seem
    > inside-out to some. For most people, this is extra work compared to writing
    > a wrapper that accepts the function and parameters together and only has a
    > single level of nesting.
    >
    > In other words
    >
    > def make_wrapper(func, param):
    > def wrapper(*args, **kwds):
    > for i in range(param):
    > func(*args, **kwds)
    > return wrapper
    >
    > def f(x): print(x)
    > f = make_wrapper(f, 2)
    > f('simple')
    >
    > # is simpler, at least for some people, than the following
    > # which does essentially the same thing.
    >
    > def make_outer(param):
    > def make_inner(func):
    > def wrapper(*args, **kwds):
    > for i in range(param):
    > func(*args, **kwds)
    > return wrapper
    > return make_inner
    >
    > @make_outer(2)
    > def f(x): print(x)
    > f('complex')
    >
    > Is the gain of not repeating the wrapped function name twice in the post-def
    > wrapping call, and the gain of knowing the function will be wrapped before
    > reading the def, worth the pain of currying the wrapper maker?


    If only there were a conceptually simpler way to do this. Actually,
    there is. I give you: metadecorators!

    First, the simple, non-parameterized case:

    from functools import partial

    def make_wrapper(wrapper):
    return lambda wrapped: partial(wrapper, wrapped)

    With that simple function buried in a utility module somewhere, we can do:

    @make_wrapper
    def simple_decorator(func, *args, **kwargs):
    do_stuff()
    result = func(*args, **kwargs)
    do_more_stuff()
    return result

    Which I think is certainly easier to understand than the nested
    functions approach. Parameterized decorators are not much more
    difficult this way. This function:

    def make_parameterized_wrapper(wrapper):
    return lambda *params: lambda wrapped: partial(wrapper, wrapped, params)

    enables us to write:

    @make_parameterized_wrapper
    def complex_decorator(func, (param1, param2, param3), *args, **kwargs):
    do_stuff(param1, param2)
    result = func(*args, **kwargs)
    do_more_stuff(param2, param3)
    return result

    And now we have a fancy parameterized decorator that again requires no
    thinking about nested functions at all. Sadly, that last bit of
    syntax will only work in Python 2; tuple parameter unpacking was
    removed in Python 3. It's not a complicated upgrade path, however:

    @make_parameterized_wrapper
    def complex_decorator(func, params, *args, **kwargs):
    (param1, param2, param3) = params
    do_stuff(param1, param2)
    result = func(*args, **kwargs)
    do_more_stuff(param2, param3)
    return result

    Cheers,
    Ian
     
    Ian Kelly, Sep 14, 2012
    #10
  11. Re: Decorators not worth the effort

    On Fri, 14 Sep 2012 15:16:47 -0600, Ian Kelly wrote:

    > If only there were a conceptually simpler way to do this. Actually,
    > there is. I give you: metadecorators!

    [code snipped but shown below]
    > Which I think is certainly easier to understand than the nested
    > functions approach.


    Maybe for you, but to me it is a big ball of mud. I have no idea how this
    is supposed to work! At a quick glance, I would have sworn that it
    *can't* work, since simple_decorator needs to see multiple arguments but
    only receives one, the function to be decorated. And yet it does work:

    py> from functools import partial
    py> def make_wrapper(wrapper):
    .... return lambda wrapped: partial(wrapper, wrapped)
    ....
    py> @make_wrapper
    .... def simple_decorator(func, *args, **kwargs):
    .... print "Entering decorated function"
    .... result = func(*args, **kwargs)
    .... print "Exiting decorated function"
    .... return result
    ....
    py> @simple_decorator
    .... def my_function(a, b, c):
    .... """Doc string"""
    .... return a+b+c
    ....
    py> my_function(1, 2, 3)
    Entering decorated function
    Exiting decorated function
    6

    So to me, this is far more magical than nested functions. If I saw this
    in t requires me to hunt through your library for the "simple function
    buried in a utility module somewhere" (your words), instead of seeing
    everything needed in a single decorator factory function. It requires
    that I understand how partial works, which in my opinion is quite tricky.
    (I never remember how it works or which arguments get curried.)

    And the end result is that the decorated function is less debugging-
    friendly than I demand: it is an anonymous partial object instead of a
    named function, and the doc string is lost. And it is far from clear to
    me how to modify your recipe to use functools.wraps in order to keep the
    name and docstring, or even whether I *can* use functools.wraps.

    I dare say I could answer all those questions with some experimentation
    and research. But I don't think that your "metadecorator" using partial
    is *inherently* more understandable than the standard decorator approach:

    def simple_decorator2(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
    print "Entering decorated function"
    result = func(*args, **kwargs)
    print "Exiting decorated function"
    return result
    return inner

    This is no more complex than yours, and it keeps the function name and
    docstring.


    > Parameterized decorators are not much more
    > difficult this way. This function:

    [snip code]
    > And now we have a fancy parameterized decorator that again requires no
    > thinking about nested functions at all.


    Again, at the cost of throwing away the function name and docstring.

    I realise that a lot of this boils down to personal preference, but I
    just don't think that nested functions are necessarily that hard to
    grasp, so I prefer to see as much of the decorator logic to be in one
    place (a nested decorator function) rather than scattered across two
    separate decorators plus partial.




    --
    Steven
     
    Steven D'Aprano, Sep 15, 2012
    #11
  12. Jean-Michel Pichavant

    Dwight Hutto Guest

    Re: Decorators not worth the effort

    On Fri, Sep 14, 2012 at 2:40 AM, Dieter Maurer <> wrote:
    >> On Sep 14, 3:54 am, Jean-Michel Pichavant <>
    >> wrote:
    >>> I don't like decorators, I think they're not worth the mental effort.

    >
    > Fine.
    >
    > I like them because they can vastly improve reusability and drastically
    > reduce redundancies (which I hate). Improved reusability and
    > reduced redundancies can make applications more readable, easier
    > to maintain and faster to develop.


    Reduce redundancy, is argumentative.

    To me, a decorator, is no more than a logging function. Correct me if
    I'm wrong. It throws things at a functyion designed to watch other
    functions.

    The necessity for more than one decorator with if /else statements
    seems redundant, but I haven't had to use them that much recently.

    >
    > --
    > http://mail.python.org/mailman/listinfo/python-list




    --
    Best Regards,
    David Hutto
    CEO: http://www.hitwebdevelopment.com
     
    Dwight Hutto, Sep 15, 2012
    #12
  13. Re: Decorators not worth the effort

    Dwight Hutto wrote at 2012-9-14 23:42 -0400:
    > ...
    >Reduce redundancy, is argumentative.
    >
    >To me, a decorator, is no more than a logging function. Correct me if
    >I'm wrong.


    Well, it depends on how you are using decorators and how complex
    your decorators are. If what you are using as decorating function
    it really trivial, as trivial as "@<decoratorname>", then you
    do not gain much.

    But your decorator functions need not be trivial.
    An example: in a recent project,
    I have implemented a SOAP webservice where most services depend
    on a valid session and must return specified fields even when
    (as in the case of an error) there is no senseful value.
    Instead of putting into each of those function implementations
    the check "do I have a valid session?" and at the end
    "add required fields not specified", I opted for the following
    decorator:

    def valid_session(*fields):
    ! fields = ("errorcode",) + fields
    @decorator
    def valid_session(f, self, sessionkey, *args, **kw):
    ! s = get_session(sessionkey)
    ! if not s.get("authenticated", False):
    ! rd = {"errorcode": u"1000"}
    ! else:
    ! rd = f(self, sessionkey, *args, **kw)
    ! return tuple(rd.get(field, DEFAULTS.get(field, '')) for field in fields)
    return valid_session

    The lines starting with "!" represent the logic encapsulated by the
    decorator -- the logic, I would have to copy into each function implementation
    without it.

    I then use it this way:

    @valid_session()
    def logout(self, sessionkey):
    s = get_session(sessionkey)
    s["authenticated"] = False
    return {}

    @valid_session("amountavail")
    def getStock(self, sessionkey, customer, item, amount):
    info = self._get_article(item)
    return {u"amountavail":info["deliverability"] and u"0" or u"1"}

    @valid_session("item", "shortdescription", "pe", "me", "min", "price", "vpe", "stock", "linkpicture", "linkdetail", "linklist", "description", "tax")
    def fetchDetail(self, sessionkey, customer, item):
    return self._get_article(item)
    ...

    I hope you can see that at least in this example, the use of the decorator
    reduces redundancy and highly improves readability -- because
    boilerplate code (check valid session, add default values for unspecified
    fields) is not copied over and over again but isolated in a single place.


    The example uses a second decorator ("@decorator") --
    in the decorator definition itself. This decorator comes from the
    "decorator" module, a module facilitating the definition of signature
    preserving decorators (important in my context): such a decorator
    ensures that the decoration result has the same parameters as the
    decorated function. To achieve this, complex Python implementation
    details and Python's introspection must be used. And I am very
    happy that I do not have to reproduce this logic in my decorator
    definitions but just say "@decorator" :)


    Example 3: In another project, I had to implement a webservice
    where most of the functions should return "json" serialized data
    structures. As I like decorators, I chose a "@json" decorator.
    Its definition looks like this:

    @decorator
    def json(f, self, *args, **kw):
    r = f(self, *args, **kw)
    self.request.response.setHeader(
    'content-type',
    # "application/json" made problems with the firewall,
    # try "text/json" instead
    #'application/json; charset=utf-8'
    'text/json; charset=utf-8'
    )
    return udumps(r)

    It calls the decorated function, then adds the correct "content-type"
    header and finally returns the "json" serialized return value.

    The webservice function definitions then look like:

    @json
    def f1(self, ....):
    ....

    @json
    def f2(self, ...):
    ....

    The function implementions can concentrate on their primary task.
    The "json" decorator" tells that the result is (by magic specified
    elsewhere) turned into a "json" serialized value.

    This example demontrates the improved maintainability (caused by
    the redundancy reduction): the "json rpc" specification stipulates
    the use of the "application/json" content type. Correspondingly,
    I used this content-type header initially. However, many enterprise
    firewalls try to protect against viruses by banning "application/*"
    responses -- and in those environments, my initial webservice
    implementation did not work. Thus, I changed the content type
    to "text/json". Thanks to the decorator encapsulation of the
    "json result logic", I could make my change at a single place -- not littered
    all over the webservice implementation.


    And a final example: Sometimes you are interested to cache (expensive)
    function results. Caching involves non-trivial logic (determine the cache,
    determine the key, check whether the cache contains a value for the key;
    if not, call the function, cache the result). The package "plone.memoize"
    defines a set of decorators (for different caching policies) which
    which caching can be as easy as:

    @memoize
    def f(....):
    ....

    The complete caching logic is encapsulated in the tiny "@memoize" prefix.
    It tells: calls to this function are cached. The function implementation
    can concentrate on its primary task and there is no need to obscure
    the implementation by the orthogonal aspect of caching.


    I hope I could convince you that while you may not have a serious need
    for decorators, there are cases where they can be really useful.

    Should I have not yet succeeded, I suggest you read some overview
    on aspect oriented programming. I am sure, you will find there
    losts of further examples why it is a good idea to separate
    general purpose aspects (logging, monitoring, persistency, resource
    management, caching, serialization, ...) from the primary task of
    a function. Decorators provide syntactic sugur to facilitate this
    separation in Python.


    --
    Dieter
     
    Dieter Maurer, Sep 15, 2012
    #13
  14. Re: Decorators not worth the effort

    [Sorry, my Firefox destroyed the indent...

    Am 14.09.2012 22:29 schrieb Terry Reedy:

    > In other words
    >
    > def make_wrapper(func, param):
    > def wrapper(*args, **kwds):
    > for i in range(param):
    > func(*args, **kwds)
    > return wrapper
    >
    > def f(x): print(x)
    > f = make_wrapper(f, 2)
    > f('simple')
    >
    > # is simpler, at least for some people, than the following
    > # which does essentially the same thing.
    >
    > def make_outer(param):
    > def make_inner(func):
    > def wrapper(*args, **kwds):
    > for i in range(param):
    > func(*args, **kwds)
    > return wrapper
    > return make_inner
    >
    > @make_outer(2)
    > def f(x): print(x)
    > f('complex')


    For this case, my mydeco.py which I use quite often contains a

    def indirdeco(ind):
    # Update both the outer as well as the inner wrapper.
    # If we knew the inner one was to be updated with something
    # from *a, **k, we could do it. But not this way...
    @functools.wraps(ind)
    def outer(*a, **k):
    @functools.wraps(ind)
    def inner(f):
    return ind(f, *a, **k)
    return inner
    return outer

    so I can do

    @indirdeco
    def make_wrapper(func, param):
    @functools.wraps(func)
    def wrapper(*args, **kwds):
    for i in range(param):
    func(*args, **kwds)
    return wrapper

    and then nevertheless

    @make_wrapper(2)
    def f(x): print(x)

    BTW, I also have a "meta-decorator" for the other direction:

    def wrapfunction(mighty):
    """Wrap a function taking (f, *a, **k) and replace it with a
    function taking (f) and returning a function taking (*a, **k) which
    calls our decorated function.
    Other direction than indirdeco."""
    @functools.wraps(mighty)
    def wrapped_outer(inner):
    @functools.wraps(inner)
    def wrapped_inner(*a, **k):
    return mighty(inner, *a, **k)
    wrapped_inner.func = inner # keep the wrapped function
    wrapped_inner.wrapper = mighty # and the replacement
    return wrapped_inner
    wrapped_outer.func = mighty # keep this as well
    return wrapped_outer

    With this, a

    @wrapfunction
    def twice(func, *a, **k):
    return func(*a, **k), func(*a, **k)

    can be used with

    @twice
    def f(x): print (x); return x

    very nicely.


    Thomas
     
    Thomas Rachel, Sep 15, 2012
    #14
  15. Re: Decorators not worth the effort

    Steven D'Apranoæ–¼ 2012å¹´9月15日星期六UTC+8上åˆ7時39分28秒寫é“:
    > On Fri, 14 Sep 2012 15:16:47 -0600, Ian Kelly wrote:
    >
    >
    >
    > > If only there were a conceptually simpler way to do this. Actually,

    >
    > > there is. I give you: metadecorators!

    >
    > [code snipped but shown below]
    >
    > > Which I think is certainly easier to understand than the nested

    >
    > > functions approach.

    >
    >
    >
    > Maybe for you, but to me it is a big ball of mud. I have no idea how this
    >
    > is supposed to work! At a quick glance, I would have sworn that it
    >
    > *can't* work, since simple_decorator needs to see multiple arguments but
    >
    > only receives one, the function to be decorated. And yet it does work:
    >
    >
    >
    > py> from functools import partial
    >
    > py> def make_wrapper(wrapper):
    >
    > ... return lambda wrapped: partial(wrapper, wrapped)
    >
    > ...
    >
    > py> @make_wrapper
    >
    > ... def simple_decorator(func, *args, **kwargs):
    >
    > ... print "Entering decorated function"
    >
    > ... result = func(*args, **kwargs)
    >
    > ... print "Exiting decorated function"
    >
    > ... return result
    >
    > ...
    >
    > py> @simple_decorator
    >
    > ... def my_function(a, b, c):
    >
    > ... """Doc string"""
    >
    > ... return a+b+c
    >
    > ...
    >
    > py> my_function(1, 2, 3)
    >
    > Entering decorated function
    >
    > Exiting decorated function
    >
    > 6
    >
    >
    >
    > So to me, this is far more magical than nested functions. If I saw this
    >
    > in t requires me to hunt through your library for the "simple function
    >
    > buried in a utility module somewhere" (your words), instead of seeing
    >
    > everything needed in a single decorator factory function. It requires
    >
    > that I understand how partial works, which in my opinion is quite tricky.
    >
    > (I never remember how it works or which arguments get curried.)
    >
    >
    >
    > And the end result is that the decorated function is less debugging-
    >
    > friendly than I demand: it is an anonymous partial object instead of a
    >
    > named function, and the doc string is lost. And it is far from clear to
    >
    > me how to modify your recipe to use functools.wraps in order to keep the
    >
    > name and docstring, or even whether I *can* use functools.wraps.
    >
    >
    >
    > I dare say I could answer all those questions with some experimentation
    >
    > and research. But I don't think that your "metadecorator" using partial
    >
    > is *inherently* more understandable than the standard decorator approach:
    >
    >
    >
    > def simple_decorator2(func):
    >
    > @functools.wraps(func)
    >
    > def inner(*args, **kwargs):
    >
    > print "Entering decorated function"
    >
    > result = func(*args, **kwargs)
    >
    > print "Exiting decorated function"
    >
    > return result
    >
    > return inner
    >
    >
    >
    > This is no more complex than yours, and it keeps the function name and
    >
    > docstring.
    >
    >
    >
    >
    >
    > > Parameterized decorators are not much more

    >
    > > difficult this way. This function:

    >
    > [snip code]
    >
    > > And now we have a fancy parameterized decorator that again requires no

    >
    > > thinking about nested functions at all.

    >
    >
    >
    > Again, at the cost of throwing away the function name and docstring.
    >
    >
    >
    > I realise that a lot of this boils down to personal preference, but I
    >
    > just don't think that nested functions are necessarily that hard to
    >
    > grasp, so I prefer to see as much of the decorator logic to be in one
    >
    > place (a nested decorator function) rather than scattered across two
    >
    > separate decorators plus partial.
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > --
    >
    > Steven



    I think the problem is not in the replaced f.__doc__.


    def MIGHT_FAIL(f, MSG, *k, **h):

    # use MSG to determine whether to invoke f or not
    # and do an error catch here
    ....
    def innner(f): .....
    ......
    # get the right info of f here for any trapped error
    #return inner, result
    return inner
     
    88888 Dihedral, Sep 15, 2012
    #15
  16. Jean-Michel Pichavant

    Dwight Hutto Guest

    Re: Decorators not worth the effort

    On Sat, Sep 15, 2012 at 5:45 AM, 88888 Dihedral
    <> wrote:
    > Steven D'Aprano©ó 2012¦~9¤ë15¤é¬P´Á¤»UTC+8¤W¤È7®É39¤À28¬í¼g¹D¡G
    >> On Fri, 14 Sep 2012 15:16:47 -0600, Ian Kelly wrote:
    >>
    >>
    >>
    >> > If only there were a conceptually simpler way to do this. Actually,

    >>
    >> > there is. I give you: muman than humanetadecorators!

    >>
    >> [code snipped but shown below]
    >>
    >> > Which I think is certainly easier to understand than the nested

    >>
    >> > functions approach.

    >>
    >>
    >>
    >> Maybe for you, but to me it is a big ball of mud. I have no idea how this
    >>
    >> is supposed to work! At a quick glance, I would have sworn that it
    >>
    >> *can't* work, since simple_decorator needs to see multiple arguments but
    >>
    >> only receives one, the function to be decorated. And yet it does work:
    >>
    >>
    >>
    >> py> from functools import partial
    >>
    >> py> def make_wrapper(wrapper):
    >>
    >> ... return lambda wrapped: partial(wrapper, wrapped)
    >>
    >> ...
    >>
    >> py> @make_wrapper
    >>
    >> ... def simple_decorator(func, *args, **kwargs):
    >>
    >> ... print "Entering decorated function"
    >>
    >> ... result = func(*args, **kwargs)
    >>
    >> ... print "Exiting decorated function"
    >>
    >> ... return result
    >>
    >> ...
    >>
    >> py> @simple_decorator
    >>
    >> ... def my_function(a, b, c):
    >>
    >> ... """Doc string"""
    >>
    >> ... return a+b+c
    >>
    >> ...
    >>
    >> py> my_function(1, 2, 3)
    >>
    >> Entering decorated function
    >>
    >> Exiting decorated function
    >>
    >> 6
    >>
    >>
    >>
    >> So to me, this is far more magical than nested functions. If I saw this
    >>
    >> in t requires me to hunt through your library for the "simple function
    >>
    >> buried in a utility module somewhere" (your words), instead of seeing
    >>
    >> everything needed in a single decorator factory function. It requires
    >>
    >> that I understand how partial works, which in my opinion is quite tricky..
    >>
    >> (I never remember how it works or which arguments get curried.)
    >>
    >>
    >>
    >> And the end result is that the decorated function is less debugging-
    >>
    >> friendly than I demand: it is an anonymous partial object instead of a
    >>
    >> named function, and the doc string is lost. And it is far from clear to
    >>
    >> me how to modify your recipe to use functools.wraps in order to keep the
    >>
    >> name and docstring, or even whether I *can* use functools.wraps.
    >>
    >>
    >>
    >> I dare say I could answer all those questions with some experimentation
    >>
    >> and research. But I don't think that your "metadecorator" using partial
    >>
    >> is *inherently* more understandable than the standard decorator approach:
    >>
    >>
    >>
    >> def simple_decorator2(func):
    >>
    >> @functools.wraps(func)
    >>
    >> def inner(*args, **kwargs):
    >>
    >> print "Entering decorated function"
    >>
    >> result = func(*args, **kwargs)
    >>
    >> print "Exiting decorated function"
    >>
    >> return result
    >>
    >> return inner
    >>
    >>
    >>
    >> This is no more complex than yours, and it keeps the function name and
    >>
    >> docstring.
    >>
    >>
    >>
    >>
    >>
    >> > Parameterized decorators are not much more

    >>
    >> > difficult this way. This function:

    >>
    >> [snip code]
    >>
    >> > And now we have a fancy parameterized decorator that again requires no

    >>
    >> > thinking about nested functions at all.

    >>
    >>
    >>
    >> Again, at the cost of throwing away the function name and docstring.
    >>
    >>
    >>
    >> I realise that a lot of this boils down to personal preference, but I
    >>
    >> just don't think that nested functions are necessarily that hard to
    >>
    >> grasp, so I prefer to see as much of the decorator logic to be in one
    >>
    >> place (a nested decorator function) rather than scattered across two
    >>
    >> separate decorators plus partial.


    Like chi fu, allow decorators to evolve upon themselves. Like simple
    moves flow through water and allow memorization of activity through
    evidence of existence.


    --
    Best Regards,
    David Hutto
    CEO: http://www.hitwebdevelopment.com
     
    Dwight Hutto, Sep 15, 2012
    #16
  17. Re: Decorators not worth the effort

    David Huttoæ–¼ 2012å¹´9月15日星期六UTC+8下åˆ6時04分28秒寫é“:
    > On Sat, Sep 15, 2012 at 5:45 AM, 88888 Dihedral
    >
    > <> wrote:
    >
    > > Steven D'Apranoæ–¼ 2012å¹´9月15日星期六UTC+8上åˆ7時39分28秒寫é“:

    >
    > >> On Fri, 14 Sep 2012 15:16:47 -0600, Ian Kelly wrote:

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> > If only there were a conceptually simpler way to do this. Actually,

    >
    > >>

    >
    > >> > there is. I give you: muman than humanetadecorators!

    >
    > >>

    >
    > >> [code snipped but shown below]

    >
    > >>

    >
    > >> > Which I think is certainly easier to understand than the nested

    >
    > >>

    >
    > >> > functions approach.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> Maybe for you, but to me it is a big ball of mud. I have no idea how this

    >
    > >>

    >
    > >> is supposed to work! At a quick glance, I would have sworn that it

    >
    > >>

    >
    > >> *can't* work, since simple_decorator needs to see multiple arguments but

    >
    > >>

    >
    > >> only receives one, the function to be decorated. And yet it does work:

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> py> from functools import partial

    >
    > >>

    >
    > >> py> def make_wrapper(wrapper):

    >
    > >>

    >
    > >> ... return lambda wrapped: partial(wrapper, wrapped)

    >
    > >>

    >
    > >> ...

    >
    > >>

    >
    > >> py> @make_wrapper

    >
    > >>

    >
    > >> ... def simple_decorator(func, *args, **kwargs):

    >
    > >>

    >
    > >> ... print "Entering decorated function"

    >
    > >>

    >
    > >> ... result = func(*args, **kwargs)

    >
    > >>

    >
    > >> ... print "Exiting decorated function"

    >
    > >>

    >
    > >> ... return result

    >
    > >>

    >
    > >> ...

    >
    > >>

    >
    > >> py> @simple_decorator

    >
    > >>

    >
    > >> ... def my_function(a, b, c):

    >
    > >>

    >
    > >> ... """Doc string"""

    >
    > >>

    >
    > >> ... return a+b+c

    >
    > >>

    >
    > >> ...

    >
    > >>

    >
    > >> py> my_function(1, 2, 3)

    >
    > >>

    >
    > >> Entering decorated function

    >
    > >>

    >
    > >> Exiting decorated function

    >
    > >>

    >
    > >> 6

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> So to me, this is far more magical than nested functions. If I saw this

    >
    > >>

    >
    > >> in t requires me to hunt through your library for the "simple function

    >
    > >>

    >
    > >> buried in a utility module somewhere" (your words), instead of seeing

    >
    > >>

    >
    > >> everything needed in a single decorator factory function. It requires

    >
    > >>

    >
    > >> that I understand how partial works, which in my opinion is quite tricky.

    >
    > >>

    >
    > >> (I never remember how it works or which arguments get curried.)

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> And the end result is that the decorated function is less debugging-

    >
    > >>

    >
    > >> friendly than I demand: it is an anonymous partial object instead of a

    >
    > >>

    >
    > >> named function, and the doc string is lost. And it is far from clear to

    >
    > >>

    >
    > >> me how to modify your recipe to use functools.wraps in order to keep the

    >
    > >>

    >
    > >> name and docstring, or even whether I *can* use functools.wraps.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> I dare say I could answer all those questions with some experimentation

    >
    > >>

    >
    > >> and research. But I don't think that your "metadecorator" using partial

    >
    > >>

    >
    > >> is *inherently* more understandable than the standard decorator approach:

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> def simple_decorator2(func):

    >
    > >>

    >
    > >> @functools.wraps(func)

    >
    > >>

    >
    > >> def inner(*args, **kwargs):

    >
    > >>

    >
    > >> print "Entering decorated function"

    >
    > >>

    >
    > >> result = func(*args, **kwargs)

    >
    > >>

    >
    > >> print "Exiting decorated function"

    >
    > >>

    >
    > >> return result

    >
    > >>

    >
    > >> return inner

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> This is no more complex than yours, and it keeps the function name and

    >
    > >>

    >
    > >> docstring.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> > Parameterized decorators are not much more

    >
    > >>

    >
    > >> > difficult this way. This function:

    >
    > >>

    >
    > >> [snip code]

    >
    > >>

    >
    > >> > And now we have a fancy parameterized decorator that again requires no

    >
    > >>

    >
    > >> > thinking about nested functions at all.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> Again, at the cost of throwing away the function name and docstring.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> I realise that a lot of this boils down to personal preference, but I

    >
    > >>

    >
    > >> just don't think that nested functions are necessarily that hard to

    >
    > >>

    >
    > >> grasp, so I prefer to see as much of the decorator logic to be in one

    >
    > >>

    >
    > >> place (a nested decorator function) rather than scattered across two

    >
    > >>

    >
    > >> separate decorators plus partial.

    >
    >
    >
    > Like chi fu, allow decorators to evolve upon themselves. Like simple
    >
    > moves flow through water and allow memorization of activity through
    >
    > evidence of existence.
    >
    >
    >
    >
    >
    > --
    >
    > Best Regards,



    The concept of decorators is just a mapping from a function to another
    function with the same name in python.


    It should be easy to be grapsed for those studied real analysis and
    functional analysis.
     
    88888 Dihedral, Sep 15, 2012
    #17
  18. Re: Decorators not worth the effort

    David Huttoæ–¼ 2012å¹´9月15日星期六UTC+8下åˆ6時04分28秒寫é“:
    > On Sat, Sep 15, 2012 at 5:45 AM, 88888 Dihedral
    >
    > <> wrote:
    >
    > > Steven D'Apranoæ–¼ 2012å¹´9月15日星期六UTC+8上åˆ7時39分28秒寫é“:

    >
    > >> On Fri, 14 Sep 2012 15:16:47 -0600, Ian Kelly wrote:

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> > If only there were a conceptually simpler way to do this. Actually,

    >
    > >>

    >
    > >> > there is. I give you: muman than humanetadecorators!

    >
    > >>

    >
    > >> [code snipped but shown below]

    >
    > >>

    >
    > >> > Which I think is certainly easier to understand than the nested

    >
    > >>

    >
    > >> > functions approach.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> Maybe for you, but to me it is a big ball of mud. I have no idea how this

    >
    > >>

    >
    > >> is supposed to work! At a quick glance, I would have sworn that it

    >
    > >>

    >
    > >> *can't* work, since simple_decorator needs to see multiple arguments but

    >
    > >>

    >
    > >> only receives one, the function to be decorated. And yet it does work:

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> py> from functools import partial

    >
    > >>

    >
    > >> py> def make_wrapper(wrapper):

    >
    > >>

    >
    > >> ... return lambda wrapped: partial(wrapper, wrapped)

    >
    > >>

    >
    > >> ...

    >
    > >>

    >
    > >> py> @make_wrapper

    >
    > >>

    >
    > >> ... def simple_decorator(func, *args, **kwargs):

    >
    > >>

    >
    > >> ... print "Entering decorated function"

    >
    > >>

    >
    > >> ... result = func(*args, **kwargs)

    >
    > >>

    >
    > >> ... print "Exiting decorated function"

    >
    > >>

    >
    > >> ... return result

    >
    > >>

    >
    > >> ...

    >
    > >>

    >
    > >> py> @simple_decorator

    >
    > >>

    >
    > >> ... def my_function(a, b, c):

    >
    > >>

    >
    > >> ... """Doc string"""

    >
    > >>

    >
    > >> ... return a+b+c

    >
    > >>

    >
    > >> ...

    >
    > >>

    >
    > >> py> my_function(1, 2, 3)

    >
    > >>

    >
    > >> Entering decorated function

    >
    > >>

    >
    > >> Exiting decorated function

    >
    > >>

    >
    > >> 6

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> So to me, this is far more magical than nested functions. If I saw this

    >
    > >>

    >
    > >> in t requires me to hunt through your library for the "simple function

    >
    > >>

    >
    > >> buried in a utility module somewhere" (your words), instead of seeing

    >
    > >>

    >
    > >> everything needed in a single decorator factory function. It requires

    >
    > >>

    >
    > >> that I understand how partial works, which in my opinion is quite tricky.

    >
    > >>

    >
    > >> (I never remember how it works or which arguments get curried.)

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> And the end result is that the decorated function is less debugging-

    >
    > >>

    >
    > >> friendly than I demand: it is an anonymous partial object instead of a

    >
    > >>

    >
    > >> named function, and the doc string is lost. And it is far from clear to

    >
    > >>

    >
    > >> me how to modify your recipe to use functools.wraps in order to keep the

    >
    > >>

    >
    > >> name and docstring, or even whether I *can* use functools.wraps.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> I dare say I could answer all those questions with some experimentation

    >
    > >>

    >
    > >> and research. But I don't think that your "metadecorator" using partial

    >
    > >>

    >
    > >> is *inherently* more understandable than the standard decorator approach:

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> def simple_decorator2(func):

    >
    > >>

    >
    > >> @functools.wraps(func)

    >
    > >>

    >
    > >> def inner(*args, **kwargs):

    >
    > >>

    >
    > >> print "Entering decorated function"

    >
    > >>

    >
    > >> result = func(*args, **kwargs)

    >
    > >>

    >
    > >> print "Exiting decorated function"

    >
    > >>

    >
    > >> return result

    >
    > >>

    >
    > >> return inner

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> This is no more complex than yours, and it keeps the function name and

    >
    > >>

    >
    > >> docstring.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> > Parameterized decorators are not much more

    >
    > >>

    >
    > >> > difficult this way. This function:

    >
    > >>

    >
    > >> [snip code]

    >
    > >>

    >
    > >> > And now we have a fancy parameterized decorator that again requires no

    >
    > >>

    >
    > >> > thinking about nested functions at all.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> Again, at the cost of throwing away the function name and docstring.

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> I realise that a lot of this boils down to personal preference, but I

    >
    > >>

    >
    > >> just don't think that nested functions are necessarily that hard to

    >
    > >>

    >
    > >> grasp, so I prefer to see as much of the decorator logic to be in one

    >
    > >>

    >
    > >> place (a nested decorator function) rather than scattered across two

    >
    > >>

    >
    > >> separate decorators plus partial.

    >
    >
    >
    > Like chi fu, allow decorators to evolve upon themselves. Like simple
    >
    > moves flow through water and allow memorization of activity through
    >
    > evidence of existence.
    >
    >
    >
    >
    >
    > --
    >
    > Best Regards,



    The concept of decorators is just a mapping from a function to another
    function with the same name in python.


    It should be easy to be grapsed for those studied real analysis and
    functional analysis.
     
    88888 Dihedral, Sep 15, 2012
    #18
  19. Jean-Michel Pichavant

    alex23 Guest

    Re: Decorators not worth the effort

    On Sep 15, 6:30 am, Terry Reedy <> wrote:
    > > On 13Sep2012 18:58, alex23 <> wrote:
    > > | On Sep 14, 3:54 am, Jean-Michel Pichavant <>
    > > | wrote:
    > > | > I don't like decorators, I think they're not worth the mental effort.
    > > |
    > > | Because passing a function to a function is a huge cognitive burden?

    >
    > For parameterized decorators, there is extra cognitive burden. See below.


    I do regret my initial criticism, for exactly this reason.
     
    alex23, Sep 17, 2012
    #19
  20. Re: Decorators not worth the effort

    Am 15.09.2012 16:18 schrieb 88888 Dihedral:

    > The concept of decorators is just a mapping from a function


    .... or class ...

    > to another function


    .... or any other object ...

    > with the same name in python.



    Thomas
     
    Thomas Rachel, Sep 18, 2012
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris

    Python for Presentations

    Chris, Apr 14, 2004, in forum: Python
    Replies:
    3
    Views:
    422
  2. andrea crotti

    Python presentations

    andrea crotti, Sep 13, 2012, in forum: Python
    Replies:
    16
    Views:
    347
    Alexander Blinne
    Sep 17, 2012
  3. andrea crotti

    Re: Python presentations

    andrea crotti, Sep 13, 2012, in forum: Python
    Replies:
    0
    Views:
    165
    andrea crotti
    Sep 13, 2012
  4. Cameron Simpson

    Re: Python presentations

    Cameron Simpson, Sep 14, 2012, in forum: Python
    Replies:
    0
    Views:
    156
    Cameron Simpson
    Sep 14, 2012
  5. Trent Nelson

    Re: Python presentations

    Trent Nelson, Sep 19, 2012, in forum: Python
    Replies:
    0
    Views:
    155
    Trent Nelson
    Sep 19, 2012
Loading...

Share This Page