Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #29057 > unrolled thread

Re: Python presentations

Started byJean-Michel Pichavant <jeanmichel@sequans.com>
First post2012-09-13 19:54 +0200
Last post2012-09-15 08:31 +0200
Articles 3 on this page of 23 — 12 participants

Back to article view | Back to comp.lang.python


Contents

  Re: Python presentations Jean-Michel Pichavant <jeanmichel@sequans.com> - 2012-09-13 19:54 +0200
    Re: Python presentations Alister <alister.ware@ntlworld.com> - 2012-09-13 18:18 +0000
    Decorators not worth the effort alex23 <wuwei23@gmail.com> - 2012-09-13 18:58 -0700
      Re: Decorators not worth the effort Cameron Simpson <cs@zip.com.au> - 2012-09-14 12:12 +1000
        Re: Decorators not worth the effort alex23 <wuwei23@gmail.com> - 2012-09-13 20:25 -0700
      Re: Decorators not worth the effort Dieter Maurer <dieter@handshake.de> - 2012-09-14 08:40 +0200
      Re: Decorators not worth the effort Terry Reedy <tjreedy@udel.edu> - 2012-09-14 16:29 -0400
        Re: Decorators not worth the effort Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2012-09-15 09:13 +0200
        Re: Decorators not worth the effort alex23 <wuwei23@gmail.com> - 2012-09-16 17:38 -0700
      Re: Decorators not worth the effort Terry Reedy <tjreedy@udel.edu> - 2012-09-14 16:31 -0400
      Re: Decorators not worth the effort Terry Reedy <tjreedy@udel.edu> - 2012-09-14 16:37 -0400
        Re: Decorators not worth the effort 88888 Dihedral <dihedral88888@googlemail.com> - 2012-09-18 16:47 -0700
        Re: Decorators not worth the effort 88888 Dihedral <dihedral88888@googlemail.com> - 2012-09-18 16:47 -0700
      Re: Decorators not worth the effort Terry Reedy <tjreedy@udel.edu> - 2012-09-14 16:33 -0400
      Re: Decorators not worth the effort Ian Kelly <ian.g.kelly@gmail.com> - 2012-09-14 15:16 -0600
        Re: Decorators not worth the effort Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-09-14 23:39 +0000
          Re: Decorators not worth the effort 88888 Dihedral <dihedral88888@googlemail.com> - 2012-09-15 02:45 -0700
            Re: Decorators not worth the effort Dwight Hutto <dwightdhutto@gmail.com> - 2012-09-15 06:04 -0400
              Re: Decorators not worth the effort 88888 Dihedral <dihedral88888@googlemail.com> - 2012-09-15 07:18 -0700
                Re: Decorators not worth the effort Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2012-09-18 14:16 +0200
              Re: Decorators not worth the effort 88888 Dihedral <dihedral88888@googlemail.com> - 2012-09-15 07:18 -0700
      Re: Decorators not worth the effort Dwight Hutto <dwightdhutto@gmail.com> - 2012-09-14 23:42 -0400
      Re: Decorators not worth the effort "Dieter Maurer" <dieter@handshake.de> - 2012-09-15 08:31 +0200

Page 2 of 2 — ← Prev page 1 [2]


#29230 — Re: Decorators not worth the effort

From88888 Dihedral <dihedral88888@googlemail.com>
Date2012-09-15 07:18 -0700
SubjectRe: Decorators not worth the effort
Message-ID<mailman.751.1347718701.27098.python-list@python.org>
In reply to#29216
David Hutto於 2012年9月15日星期六UTC+8下午6時04分28秒寫道:
> On Sat, Sep 15, 2012 at 5:45 AM, 88888 Dihedral
> 
> <dihedral88888@googlemail.com> 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.
  

[toc] | [prev] | [next] | [standalone]


#29202 — Re: Decorators not worth the effort

FromDwight Hutto <dwightdhutto@gmail.com>
Date2012-09-14 23:42 -0400
SubjectRe: Decorators not worth the effort
Message-ID<mailman.731.1347680541.27098.python-list@python.org>
In reply to#29097
On Fri, Sep 14, 2012 at 2:40 AM, Dieter Maurer <dieter@handshake.de> wrote:
>> On Sep 14, 3:54 am, Jean-Michel Pichavant <jeanmic...@sequans.com>
>> 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

[toc] | [prev] | [next] | [standalone]


#29209 — Re: Decorators not worth the effort

From"Dieter Maurer" <dieter@handshake.de>
Date2012-09-15 08:31 +0200
SubjectRe: Decorators not worth the effort
Message-ID<mailman.738.1347693346.27098.python-list@python.org>
In reply to#29097
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

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.python


csiph-web