Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Python presentations

219 views
Skip to first unread message

andrea crotti

unread,
Sep 13, 2012, 12:00:19 PM9/13/12
to python-list
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?

John Gordon

unread,
Sep 13, 2012, 12:06:05 PM9/13/12
to
In <mailman.617.13475520...@python.org> andrea crotti <andrea....@gmail.com> writes:

> For my experience if I only see code in slides I tend not to believe
> that it works somehow

Presumably you will have some credibility with your audience so they won't
just assume you're making it up?

I think slides would be fine.

--
John Gordon A is for Amy, who fell down the stairs
gor...@panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"

mblume

unread,
Sep 13, 2012, 12:26:17 PM9/13/12
to
Am Thu, 13 Sep 2012 17:00:19 +0100 schrieb andrea crotti:
>
> I have to give a couple of Python presentations in the next weeks, and
> I'm still thinking what is the best approach.
>
My idea for an introductory presentation of python was to prepare some
code snippets (all valid python), show them in the editor, explain them,
then run in a console.

Beginners could then use these code snippets for their own experiments.

HTH
Martin

andrea crotti

unread,
Sep 13, 2012, 1:13:43 PM9/13/12
to William R. Wing (Bill Wing), python-list
2012/9/13 William R. Wing (Bill Wing) <w...@mac.com>:
>
> [byte]
>
> Speaking from experience as both a presenter and an audience member, please be sure that anything you demo interactively you include in your slide deck (even if only as an addendum). I assume your audience will have access to the deck after your talk (on-line or via hand-outs), and you want them to be able to go home and try it out for themselves.
>
> Nothing is more frustrating than trying to duplicate something you saw a speaker do, and fail because of some detail you didn't notice at the time of the talk. A good example is one that was discussed on the matplotlib-users list several weeks ago:
>
> http://www.loria.fr/~rougier/teaching/matplotlib/
>
> -Bill


Yes that's a good point thanks, in general everything is already in a
git repository, now only in my dropbox but later I will make it
public.

Even the code that I should write there should already written anyway,
and to make sure everything is available I could use the save function
of IPython and add it to the repository...

In general I think that explaining code on a slide (if it involves
some new concepts in particular) it's better, but then showing what it
does it's always a plus.

It's not the same if you say this will go 10x faster than the previous
one, and showing that it actually does on your machine..

William R. Wing (Bill Wing)

unread,
Sep 13, 2012, 12:16:17 PM9/13/12
to andrea crotti, python-list, William R. Wing (Bill Wing)
On Sep 13, 2012, at 12:00 PM, andrea crotti <andrea....@gmail.com> wrote:

> 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).


Jean-Michel Pichavant

unread,
Sep 13, 2012, 1:54:44 PM9/13/12
to andrea crotti, python-list
----- 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

Alister

unread,
Sep 13, 2012, 2:18:18 PM9/13/12
to
> 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.

That is a v good suggestion.
the best presentation I ever attended was one on using an emergency life
raft presented by a member of the local sailing club (I was a scuba diver
at the time & our club was lending them some pool time)

The whole presentation consisted of a sequence of questions fired at the
audience to get them to think the problem trough & arrive at the correct
sequence of events. Genius

--
The best prophet of the future is the past.

88888 Dihedral

unread,
Sep 13, 2012, 3:01:17 PM9/13/12
to
mblume於 2012年9月14日星期五UTC+8上午12時26分17秒寫道:
I'll contribute one point in Python.

def powerlist(x, n):
# n is a natural number
result=[]
y=1
for i in xrange(n):
result.append(y)
y*=x
return result # any object in the local function can be returned


Alexander Blinne

unread,
Sep 13, 2012, 6:33:43 PM9/13/12
to
On 13.09.2012 21:01, 88888 Dihedral wrote:
> def powerlist(x, n):
> # n is a natural number
> result=[]
> y=1
> for i in xrange(n):
> result.append(y)
> y*=x
> return result # any object in the local function can be returned

def powerlist(x, n):
result=[1]
for i in xrange(n-1):
result.append(result[-1]*x)
return result

def powerlist(x,n):
if n==1:
return [1]
p = powerlist(x,n-1)
return p + [p[-1]*x]

Chris Angelico

unread,
Sep 13, 2012, 6:38:43 PM9/13/12
to pytho...@python.org
Eh, much simpler.

def powerlist(x,n):
return [x*i for i in xrange(n-1)]

But you're responding to a bot there. Rather clever as bots go, though.

ChrisA

Miki Tebeka

unread,
Sep 13, 2012, 6:58:26 PM9/13/12
to python-list
> What do you think work best in general?
I find typing during class (other than small REPL examples) time consuming and error prone.

What works well for me is to create a slidy HTML presentation with asciidoc, then I can include code snippets that can be also run from the command line.
(Something like:

[source,python,numbered]
---------------------------------------------------
include::src/sin.py[]
---------------------------------------------------

Output example: http://i.imgur.com/Aw9oQ.png
)

Let me know if you're interested and I'll send you a example project.

HTH,
--
Miki

Miki Tebeka

unread,
Sep 13, 2012, 6:58:26 PM9/13/12
to comp.lan...@googlegroups.com, python-list
> What do you think work best in general?

Andrea Crotti

unread,
Sep 13, 2012, 7:15:49 PM9/13/12
to Miki Tebeka, python-list, comp.lan...@googlegroups.com
Yes please send me something and I'll have a look.
For my slides I'm using hieroglyph:
http://heiroglyph.readthedocs.org/en/latest/index.html

which works with sphinx, so in theory I might be able to run the code as
well..

But in general probably the best way is to copy and paste in a ipython
session, to show
that what I just explained actually works as expected..

Cameron Simpson

unread,
Sep 13, 2012, 7:46:40 PM9/13/12
to andrea crotti, python-list
On 13Sep2012 17:00, andrea crotti <andrea....@gmail.com> wrote:
| 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.

Slides first.

My own experience is that someone typing code where I've not seen at
least a summary explaination ahead of time slides straight off my brain.

Ideally, two projectors: the current slides and an interactive python
environment for demos. That way people can cross reference.

But otherwise: a few slides, then a short demo if what was just spoken
about, then slides...
--
Cameron Simpson <c...@zip.com.au>

Standing on the faces of midgets, I can see for yards.
- David N Stivers D0D#857 <st...@stat.rice.edu>

alex23

unread,
Sep 13, 2012, 9:58:10 PM9/13/12
to
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.

Because passing a function to a function is a huge cognitive burden?

Cameron Simpson

unread,
Sep 13, 2012, 10:12:11 PM9/13/12
to alex23, pytho...@python.org
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 <c...@zip.com.au>

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

alex23

unread,
Sep 13, 2012, 11:25:19 PM9/13/12
to
On Sep 14, 12:12 pm, Cameron Simpson <c...@zip.com.au> wrote:
> On 13Sep2012 18:58, alex23 <wuwe...@gmail.com> 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.
> |
> | 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 :)

88888 Dihedral

unread,
Sep 14, 2012, 1:57:54 AM9/14/12
to pytho...@python.org
Chris Angelico於 2012年9月14日星期五UTC+8上午6時39分25秒寫道:
I do not object the list comprehension in concept.
But I have to convert python code to cython from time to time.

Well, this imposes some coding style definitely.



88888 Dihedral

unread,
Sep 14, 2012, 1:57:54 AM9/14/12
to comp.lan...@googlegroups.com, pytho...@python.org
Chris Angelico於 2012年9月14日星期五UTC+8上午6時39分25秒寫道:

Dieter Maurer

unread,
Sep 14, 2012, 2:40:55 AM9/14/12
to pytho...@python.org
> 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.

Jean-Michel Pichavant

unread,
Sep 14, 2012, 5:28:22 AM9/14/12
to pytho...@python.org, alex23
> --
> http://mail.python.org/mailman/listinfo/python-list
>

I was expecting that. 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).

I wrote the following one, used to decorate any function that access an equipment, it raises an exception when the timeout expires. The timeout is adapted to the platform, ASIC of FPGA so people don't need to specify everytime one timeout per platform.

In the end it would replace

def boot(self, timeout=15):
if FPGA:
self.sendCmd("bootMe", timeout=timeout*3)
else:
self.sendCmd("bootMe", timeout=timeout)

with

@timeout(15)
def boot(self, timeout=None):
self.sendCmd("bootMe", timeout)

I wrote a nice documentation with sphinx to explain this, how to use it, how it can improve code. After spending hours on the decorator + doc, feedback from my colleagues : What the F... !!

Decorators are very python specific (probably exists in any dynamic language though, I don't know), in some environment where people need to switch from C to python everyday, decorators add python magic that not everyone is familiar with. For example everyone in the team is able to understand and debug the undecorated version of the above boot method. I'm the only one capable of reading the decorated version. And don't flame my colleagues, they're amazing people (just in case they're reading this :p) who are not python developers, more of users.

Hence my original "decorators are not worth the mental effort". Context specific I must admit.

Cheers,

JM

PS : Here's the decorator, just to give you an idea about how it looks. Small piece of code, but took me more than 2 hours to write it. I removed some sensible parts so I don't expect it to run.

class timeout(object):
"""Substitute the timeout keyword argument with the appropriate value"""
FACTORS = {
IcebergConfig().platform.ASIC : 1,
IcebergConfig().platform.FPGA : 3,
}

def __init__(self, asic, fpga=None, palladium=None):
self.default = asic
self.fpga = fpga

def _getTimeout(self):
platform = config().platform
factor = self.FACTORS[platform.value]
timeout = {
platform.ASIC : self.default*factor,
platform.FPGA : self.fpga or self.default*factor,
}[platform.value]
return timeout

def __call__(self, func):
def decorated(*args, **kwargs):
names, _, _, defaults = inspect.getargspec(func)
defaults = defaults or []
if 'timeout' not in names:
raise ValueError('A "timeout" keyword argument is required')
if 'timeout' not in kwargs: # means the timeout keyword arg is not in the call
index = names.index('timeout')
argsLength = (len(names) - len(defaults))
if index < argsLength:
raise NotImplementedError('This decorator does not support non keyword "timeout" argument')
if index > len(args)-1: # means the timeout has not be passed using a pos argument
timeoutDef = defaults[index-argsLength]
if timeoutDef is not None:
_log.warning("Decorating a function with a default timeout value <> None")
kwargs['timeout'] = self._getTimeout()
else:
_log.warning('Timeout value specified during the call, please check "%s" @timeout decorator.' % func.__name__)
ret = func(*args, **kwargs)
return ret
return decorated

Duncan Booth

unread,
Sep 14, 2012, 7:26:10 AM9/14/12
to
Jean-Michel Pichavant <jeanm...@sequans.com> wrote:

> I wrote the following one, used to decorate any function that access
> an equipment, it raises an exception when the timeout expires. The
> timeout is adapted to the platform, ASIC of FPGA so people don't need
> to specify everytime one timeout per platform.
>
> In the end it would replace
>
> def boot(self, timeout=15):
> if FPGA:
> self.sendCmd("bootMe", timeout=timeout*3)
> else:
> self.sendCmd("bootMe", timeout=timeout)
>
> with
>
> @timeout(15)
> def boot(self, timeout=None):
> self.sendCmd("bootMe", timeout)
>
> I wrote a nice documentation with sphinx to explain this, how to use
> it, how it can improve code. After spending hours on the decorator +
> doc, feedback from my colleagues : What the F... !!
>

I'd agree with your colleagues. How are you going to ensure that all
relevant functions are decorated and yet no decorated function ever
calls another decorated one?

From the code you posted it would seem appropriate that the adjustment
of the timeout parameter happen in the `sendCmd()` method itself and
nowhere else. Alternatively use named values for different categories of
timeouts and adjust them on startup so instead of a default of `timeout=
15` you would have a default `timeout=MEDIUM_TIMEOUT` or whatever name
is appropriate.

--
Duncan Booth http://kupuguy.blogspot.com

Alexander Blinne

unread,
Sep 14, 2012, 7:47:57 AM9/14/12
to
On 14.09.2012 00:38, Chris Angelico wrote:
> On Fri, Sep 14, 2012 at 8:33 AM, Alexander Blinne <ne...@blinne.net> wrote:
>> def powerlist(x,n):
>> if n==1:
>> return [1]
>> p = powerlist(x,n-1)
>> return p + [p[-1]*x]
>
> Eh, much simpler.
>
> def powerlist(x,n):
> return [x*i for i in xrange(n-1)]

I suppose you meant:

def powerlist(x,n):
return [x**i for i in xrange(n-1)]

But this is less efficient, because it needs more multiplications (see
Horner's method)

Steven D'Aprano

unread,
Sep 14, 2012, 8:01:57 AM9/14/12
to
On Fri, 14 Sep 2012 11:28:22 +0200, Jean-Michel Pichavant wrote:

> PS : Here's the decorator, just to give you an idea about how it looks.
> Small piece of code, but took me more than 2 hours to write it. I
> removed some sensible parts so I don't expect it to run.

[snip timeout class]

Holy over-engineering Batman!!!

No wonder you don't think much of decorators, if this example of overkill
is what you consider typical of them. It does much, much more than the
simple code you were replacing:

def boot(self, timeout=15):
if FPGA:
self.sendCmd("bootMe", timeout=timeout*3)
else:
self.sendCmd("bootMe", timeout=timeout)

# becomes:

@timeout(15)
def boot(self, timeout=None):
self.sendCmd("bootMe", timeout)


Most of my decorator functions are under a dozen lines. And that's the
complicated ones!

Here's my solution to the example you gave:




# Untested!
def timeout(t=15):
# Decorator factory. Return a decorator to actually do the work.
if FPGA:
t *= 3
def decorator(func):
@functools.wraps(func)
def inner(self, timeout):
self.sendCmd("bootMe", timeout=t)
return inner
return decorator


I reckon that will pretty much do what your example showed. Of course,
once you start adding more and more functionality above the simple code
shown above (arbitrary platforms, argument checking of the decorated
function, logging, etc.) you're going to get a much more complex
decorator. On the other hand, YAGNI.

http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it


--
Steven

Ulrich Eckhardt

unread,
Sep 14, 2012, 7:49:00 AM9/14/12
to
Am 14.09.2012 11:28, schrieb Jean-Michel Pichavant:
> 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).
>
> I wrote the following one, used to decorate any function that access
> an equipment, it raises an exception when the timeout expires. The
> timeout is adapted to the platform, ASIC of FPGA so people don't need
> to specify everytime one timeout per platform.
>
> In the end it would replace
>
> def boot(self, timeout=15):
> if FPGA:
> self.sendCmd("bootMe", timeout=timeout*3)
> else:
> self.sendCmd("bootMe", timeout=timeout)
>
> with
>
> @timeout(15)
> def boot(self, timeout=None):
> self.sendCmd("bootMe", timeout)
>
> I wrote a nice documentation with sphinx to explain this, how to use
> it, how it can improve code. After spending hours on the decorator +
> doc, feedback from my colleagues : What the F... !!

Quite honestly: I think like your colleagues in this case and that in
this case the decorator doesn't improve the code. Instead, I would
probably have added a _get_timeout() function that takes care of
adjusting the argument passed to the function according to the
underlying hardware target.

To be less abstract, the particular problem I have with your approach is
that I can't even guess what your code means, let alone what parameters
it actually takes. If you had written

@default_timeout(15)
def boot(self, timeout=None):

instead, I would have been able to guess. OTOH, then again I would have
wondered why you used a decorator to create a default argument when
there is builtin support for specifying default arguments for functions.

Maybe you could get away with a decorator like this:

@adjust_timeout
def boot(self, timeout=2.5):

The idea is that the decorator modifies the timeout value passed to the
function (or maybe just modifies the default value?) according to the
underlying hardware.


> Decorators are very python specific (probably exists in any dynamic
> language though, I don't know), in some environment where people need
> to switch from C to python everyday, decorators add python magic that
> not everyone is familiar with.

The same could be said for classes, iterators, significant whitespace,
docstrings, lambdas. I think that this was just a bad example but it
doesn't prove that decorators are worthless. Decorators are useful tools
if they do something to a function, like doing something before or after
the actual code, or modifying the context in which the code is called.
Just setting a default parameter is possible as you have proved, but
it's IMHO not a good use case.

A bit more specific to your case, adding a timeout decorator would
actually make much more sense if it transparently invoked the actual
function in a second thread and the calling thread stops waiting for
completion and raises an error after that timeout. This has the distinct
advantage that the code doing the actual communication doesn't have any
timeout handling code inside.

I'm currently doing something similar here though I only monitor a TCP
connection that is used for some telnet-style requests. Every function
making a request over TCP is decorated with @_check_connection. That
decorator does two things:
1. It checks for an existing fatal connection error.
2. It runs the request and filters resulting errors for fatal connection
errors.

The decorator looks like this:

def _check_connection(fn):
@functools.wraps(fn)
def wrapper(self, *args, **kwargs):
# check for sticky connection errors
if self._connection_error:
raise self._connection_error
# run actual function
try:
return fn(self, *args, **kwargs)
catch RequestFailed:
# The other side signalled a failure, but
# further requests can still succeed.
raise
catch ConnectionError, e:
# The connection is broken beyond repair.
# Store sticky connection and forward.
self._connection_error = e
raise
return wrapper

I have had other programmers here write such requests and they blindly
copied the decorator from existing code. This works because the code
inside that converts/formats/parses the inputs and outputs is completely
unaware of the connection monitoring. Otherwise, I don't think anyone
could explain what this decorator does, but they don't have to
understand it either. It just works.

I wish you a nice weekend!

Uli

Chris Angelico

unread,
Sep 14, 2012, 8:19:22 AM9/14/12
to pytho...@python.org
Err, yes, I did mean ** there. The extra multiplications may be
slower, but which is worse? Lots of list additions, or lots of integer
powers? In the absence of clear and compelling evidence, I'd be
inclined to go with the list comp - and what's more, to skip this
function altogether and use the list comp directly where it's needed.

ChrisA

Tim Chase

unread,
Sep 14, 2012, 9:06:53 AM9/14/12
to Steven D'Aprano, pytho...@python.org
On 09/14/12 07:01, Steven D'Aprano wrote:
> [snip timeout class]
>
> Holy over-engineering Batman!!!
>
> No wonder you don't think much of decorators,
[snip]

> Most of my decorator functions are under a dozen lines. And that's the
> complicated ones!


As are mine, and a sizable chunk of those under-a-dozen-lines are
somewhat boilerplate like using @functools.wraps inside, actual def
of the function, and returning that function. :-)

-tkc



Jean-Michel Pichavant

unread,
Sep 14, 2012, 9:22:26 AM9/14/12
to duncan booth, pytho...@python.org
> --
> http://mail.python.org/mailman/listinfo/python-list

All functions set different timeout values, I cannot use a DEFAULT_VALUE.
All functions are design in the same way:

def doSomeAction(self, timeout):
preprocess()
self.sendCmd('relatedAction', timeout) # send the command to the device CLI interface
postprocess()

Ultimately, the goal is to have something like

@timeout(2)
def doAction1

@timeout(4)
def doAction2

@timeout(12)
def doAction3

and so on... (1 second is important, because there's a platform I remove from my example, didn't want to advertise publicly tech used by the company, that runs 1000 times slower)

Additionally, the multiple check I run within the decorator is for consistency check and argument checking. I though it was a good idea because our python engine is used by a dozen of engineers to control equipment, and any misuse of this new decorator would lead to badly configured timeouts with heavy consequences on the test sessions. Sometimes a RTFM is not enough, when you need to make this work, you slip on your Batman costume like Steven suggested, and you save the day (or so I though :) ) by raising nice exceptions about missing keyword argument.

But let's forget about my poor example, I end up describing my life which is pretty pointless.

Here's Steven example:

# Untested!
def timeout(t=15):
# Decorator factory. Return a decorator to actually do the work.
if FPGA:
t *= 3
def decorator(func):
@functools.wraps(func)
def inner(self, timeout):
self.sendCmd("bootMe", timeout=t)
return inner
return decorator

I can assure you, that for some python users, it's is not easy to understand what it does, this function returning a function which returns another (wrapped) function. It requires some effort.

JM

andrea crotti

unread,
Sep 14, 2012, 10:12:26 AM9/14/12
to Jean-Michel Pichavant, pytho...@python.org, duncan booth
I think one very nice and simple example of how decorators can be used is this:

def memoize(f, cache={}, *args, **kwargs):
def _memoize(*args, **kwargs):
key = (args, str(kwargs))
if not key in cache:
cache[key] = f(*args, **kwargs)

return cache[key]

return _memoize

def fib(n):
if n <= 1:
return 1
return fib(n-1) + fib(n-2)

@memoize
def fib_memoized(n):
if n <= 1:
return 1
return fib_memoized(n-1) + fib_memoized(n-2)


The second fibonacci looks exactly the same but while the first is
very slow and would generate a stack overflow the second doesn't..

I might use this example for the presentation, before explaining what it is..

Chris Angelico

unread,
Sep 14, 2012, 10:41:01 AM9/14/12
to pytho...@python.org
On Sat, Sep 15, 2012 at 12:12 AM, andrea crotti
<andrea....@gmail.com> wrote:
> def fib(n):
> if n <= 1:
> return 1
> return fib(n-1) + fib(n-2)
>
> @memoize
> def fib_memoized(n):
> if n <= 1:
> return 1
> return fib_memoized(n-1) + fib_memoized(n-2)
>
>
> The second fibonacci looks exactly the same but while the first is
> very slow and would generate a stack overflow the second doesn't..

Trouble is, you're starting with a pretty poor algorithm. It's easy to
improve on what's poor. Memoization can still help, but I would start
with a better algorithm, such as:

def fib(n):
if n<=1: return 1
a,b=1,1
for i in range(1,n,2):
a+=b
b+=a
return b if n%2 else a

def fib(n,cache=[1,1]):
if n<=1: return 1
while len(cache)<=n:
cache.append(cache[-1] + cache[-2])
return cache[n]

Personally, I don't mind (ab)using default arguments for caching, but
you could do the same sort of thing with a decorator if you prefer. I
think the non-decorated non-recursive version is clear and efficient
though.

ChrisA

Steven D'Aprano

unread,
Sep 14, 2012, 11:19:58 AM9/14/12
to
On Fri, 14 Sep 2012 15:22:26 +0200, Jean-Michel Pichavant wrote:

> Here's Steven example:
>
> # Untested!
> def timeout(t=15):
> # Decorator factory. Return a decorator to actually do the work. if
> FPGA:
> t *= 3
> def decorator(func):
> @functools.wraps(func)
> def inner(self, timeout):
> self.sendCmd("bootMe", timeout=t)
> return inner
> return decorator
>
> I can assure you, that for some python users, it's is not easy to
> understand what it does, this function returning a function which
> returns another (wrapped) function. It requires some effort.

Oh I agree. So does learning to tie your shoe-laces, learning to cook,
and learning to drive.

Learning to be a world-class chess master takes a lot of effort. Learning
about decorators does not.


--
Steven

Jean-Michel Pichavant

unread,
Sep 14, 2012, 11:35:57 AM9/14/12
to pytho...@python.org, Steven D'Aprano
I said some effort, not a lot of effort. Something else that requires some effort it to make experts realize that some things they consider trivial and easy, aren't actually for a lot of people.
Returning to my cave.

JM



andrea crotti

unread,
Sep 14, 2012, 12:15:35 PM9/14/12
to Chris Angelico, pytho...@python.org
2012/9/14 Chris Angelico <ros...@gmail.com>:
>
> Trouble is, you're starting with a pretty poor algorithm. It's easy to
> improve on what's poor. Memoization can still help, but I would start
> with a better algorithm, such as:
>
> def fib(n):
> if n<=1: return 1
> a,b=1,1
> for i in range(1,n,2):
> a+=b
> b+=a
> return b if n%2 else a
>
> def fib(n,cache=[1,1]):
> if n<=1: return 1
> while len(cache)<=n:
> cache.append(cache[-1] + cache[-2])
> return cache[n]
>
> Personally, I don't mind (ab)using default arguments for caching, but
> you could do the same sort of thing with a decorator if you prefer. I
> think the non-decorated non-recursive version is clear and efficient
> though.
>
> ChrisA
> --
> http://mail.python.org/mailman/listinfo/python-list


The poor algorithm is much more close to the mathematical definition
than the smarter iterative one.. And in your second version you
include some ugly caching logic inside it, so why not using a
decorator then?

I'm not saying that with the memoization is the "good" solution, just
that I think it's a very nice example of how to use a decorator, and
maybe a good example to start with a talk on decorators..

88888 Dihedral

unread,
Sep 14, 2012, 12:37:37 PM9/14/12
to pytho...@python.org
Chris Angelico於 2012年9月14日星期五UTC+8下午10時41分06秒寫道:
Uhn, the decorator part is good for wrapping functions in python.

For example a decorator can be used to add a layor of some
message handlings of those plain functions
to become iterators which could be used as call back functions
in a more elegant way.



88888 Dihedral

unread,
Sep 14, 2012, 12:37:37 PM9/14/12
to comp.lan...@googlegroups.com, pytho...@python.org
Chris Angelico於 2012年9月14日星期五UTC+8下午10時41分06秒寫道:

Chris Angelico

unread,
Sep 14, 2012, 1:30:12 PM9/14/12
to pytho...@python.org
On Sat, Sep 15, 2012 at 2:15 AM, andrea crotti
<andrea....@gmail.com> wrote:
> The poor algorithm is much more close to the mathematical definition
> than the smarter iterative one.. And in your second version you
> include some ugly caching logic inside it, so why not using a
> decorator then?

I learned Fibonacci as a sequence, not as a recursive definition. So
the algorithm I coded (the non-caching one) is pretty much how I
learned it in mathematics. But yes, you're right that the caching is
inherent to the second version; and yes, that's where a decorator can
make it a LOT cleaner.

As a demo of recursion and decorators, your original function pair is
definitely the best. But if you want to be able to calculate fib(n)
for any n without blowing your stack, my version will scale much more
safely.

But then again, who actually ever needs fibonacci numbers?

ChrisA

Terry Reedy

unread,
Sep 14, 2012, 4:29:25 PM9/14/12
to pytho...@python.org
On 9/13/2012 10:12 PM, Cameron Simpson wrote:
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

unread,
Sep 14, 2012, 4:31:49 PM9/14/12
to pytho...@python.org
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

unread,
Sep 14, 2012, 4:37:47 PM9/14/12
to pytho...@python.org
2nd try, hit send button by mistake before
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

unread,
Sep 14, 2012, 4:33:01 PM9/14/12
to pytho...@python.org
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 <wuw...@gmail.com> wrote:

Ian Kelly

unread,
Sep 14, 2012, 5:16:47 PM9/14/12
to Python
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

Prasad, Ramit

unread,
Sep 14, 2012, 7:14:00 PM9/14/12
to pytho...@python.org
Jean-Michel Pichavant wrote:

[snip]

> Ultimately, the goal is to have something like
>
> @timeout(2)
> def doAction1
>
> @timeout(4)
> def doAction2

[snip]

> Here's Steven example:
>
> # Untested!
> def timeout(t=15):
> # Decorator factory. Return a decorator to actually do the work.
> if FPGA:
> t *= 3
> def decorator(func):
> @functools.wraps(func)
> def inner(self, timeout):
> self.sendCmd("bootMe", timeout=t)
> return inner
> return decorator
>
> I can assure you, that for some python users, it's is not easy to understand
> what it does, this function returning a function which returns another
> (wrapped) function. It requires some effort.
>

I think it would help if it was renamed to set_timeout. And I would
not expect the Python user to need to understand how it *works*, just
to recognize what it *does* when it is used. I may not understand list's
sort method internals (beyond the use of timsort), but I know how to
use it to sort a list as I want. That is usually all I need.


For example, your colleagues just need to understand that the below
decorator is setting a timeout for the function.

@set_timeout(min=15)
def some_function():
'''blah'''
<code>


One minor note, the style of decorator you are using loses the docstring
(at least) of the original function. I would add the @functools.wraps(func)
decorator inside your decorator.

This email is confidential and subject to important disclaimers and
conditions including on offers for the purchase or sale of
securities, accuracy and completeness of information, viruses,
confidentiality, legal privilege, and legal entity disclaimers,
available at http://www.jpmorgan.com/pages/disclosures/email.

Steven D'Aprano

unread,
Sep 14, 2012, 7:39:28 PM9/14/12
to
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

Steve Howell

unread,
Sep 14, 2012, 9:13:27 PM9/14/12
to
For parameterized decorators, I've usually seen the pattern below.
Basically, you have 6 lines of boilerplate, and 2 lines of signal.
The amount of boilerplate is fairly daunting, but I like the
explicitness, and the nature of decorators is that they tend to get a
lot of reuse, so you can amortize the pain of all the boilerplate.

import functools

def hello_world(name): # non-boilerplate signature
def decorator(f):
@functools.wraps(f)
def wrapped(*args, **kw):
print 'hello', name # non-boilerplate value-add
f(*args, **kw)
return wrapped
return decorator

@hello_world('earth')
def add(x, y):
print x + y

add(2, 2)

Dwight Hutto

unread,
Sep 14, 2012, 11:42:18 PM9/14/12
to Dieter Maurer, pytho...@python.org
On Fri, Sep 14, 2012 at 2:40 AM, Dieter Maurer <die...@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

Dieter Maurer

unread,
Sep 15, 2012, 2:31:30 AM9/15/12
to Dwight Hutto, pytho...@python.org
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

Thomas Rachel

unread,
Sep 15, 2012, 3:13:16 AM9/15/12
to
[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

88888 Dihedral

unread,
Sep 15, 2012, 5:45:42 AM9/15/12
to
Steven D'Aprano於 2012年9月15日星期六UTC+8上午7時39分28秒寫道:
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


Dwight Hutto

unread,
Sep 15, 2012, 6:04:25 AM9/15/12
to 88888 Dihedral, pytho...@python.org
On Sat, Sep 15, 2012 at 5:45 AM, 88888 Dihedral
<dihedr...@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!
Like chi fu, allow decorators to evolve upon themselves. Like simple
moves flow through water and allow memorization of activity through
evidence of existence.

88888 Dihedral

unread,
Sep 15, 2012, 10:18:18 AM9/15/12
to 88888 Dihedral, pytho...@python.org
David Hutto於 2012年9月15日星期六UTC+8下午6時04分28秒寫道:
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

unread,
Sep 15, 2012, 10:18:18 AM9/15/12
to comp.lan...@googlegroups.com, pytho...@python.org, 88888 Dihedral
David Hutto於 2012年9月15日星期六UTC+8下午6時04分28秒寫道:

Alexander Blinne

unread,
Sep 16, 2012, 12:13:36 PM9/16/12
to
On 14.09.2012 14:19, Chris Angelico wrote:
> Err, yes, I did mean ** there. The extra multiplications may be
> slower, but which is worse? Lots of list additions, or lots of integer
> powers? In the absence of clear and compelling evidence, I'd be
> inclined to go with the list comp - and what's more, to skip this
> function altogether and use the list comp directly where it's needed.

I did some timing with the following versions of the function:

def powerlist1(x, n):
result=[1]
for i in xrange(n-1):
result.append(result[-1]*x)
return result

def powerlist2(x,n):
if n==1:
return [1]
p = powerlist3(x,n-1)
p.append(p[-1]*x)
return p

def powerlist3(x,n):
return [x**i for i in xrange(n)]

with Python 2.7 you are quite right, i used x=4. Below n=26 powerlist3
is the fastest version, for n>26 powerlist1 is faster, powerlist2 is
always slower than both.

With Pypy there is a completely different picture, with n<30 powerlist2
is way faster then the other two, but then powerlist1 is again faster
for greater n, somehow because now C long int cannot be used any longer.

for really big n powerlist3 always takes very much time :)

Alex

Chris Angelico

unread,
Sep 16, 2012, 12:19:58 PM9/16/12
to pytho...@python.org
On Mon, Sep 17, 2012 at 2:13 AM, Alexander Blinne <ne...@blinne.net> wrote:
> def powerlist3(x,n):
> return [x**i for i in xrange(n)]
>
> for really big n powerlist3 always takes very much time :)

I would reiterate that a really big n is a really unusual use case for
a function like this, except that... I frankly can't think of *any*
use case for it!! But for many many applications, the simplicity and
readability of a list comp instead of a function is usually going to
outweigh the performance differences.

However, it doesn't surprise me that individually raising a number to
successive powers is slower than iterative multiplication, assuming
you can't massively optimize eg with powers of 2 and bit shifts.

ChrisA

Steven D'Aprano

unread,
Sep 16, 2012, 1:35:47 PM9/16/12
to
On Sun, 16 Sep 2012 18:13:36 +0200, Alexander Blinne wrote:

> I did some timing with the following versions of the function:
>
> def powerlist1(x, n):
> result=[1]
> for i in xrange(n-1):
> result.append(result[-1]*x)
> return result
>
> def powerlist2(x,n):
> if n==1:
> return [1]
> p = powerlist3(x,n-1)
> p.append(p[-1]*x)
> return p

Is that a typo? I think you mean to make a recursive call to powerlist2,
not a non-recursive call to powerlist3.


> def powerlist3(x,n):
> return [x**i for i in xrange(n)]
>
> with Python 2.7 you are quite right, i used x=4. Below n=26 powerlist3
> is the fastest version, for n>26 powerlist1 is faster, powerlist2 is
> always slower than both.

Making powerlist2 recursive, the results I get with Python 2.7 are:


py> from timeit import Timer as T
py> x = 2.357
py> n = 8
py> t1 = T('powerlist1(x, n)',
... setup='from __main__ import powerlist1, x, n')
py> t2 = T('powerlist2(x, n)',
... setup='from __main__ import powerlist2, x, n')
py> t3 = T('powerlist3(x, n)',
... setup='from __main__ import powerlist3, x, n')
py> min(t1.repeat(number=100000, repeat=5))
0.38042593002319336
py> min(t2.repeat(number=100000, repeat=5))
0.5992050170898438
py> min(t3.repeat(number=100000, repeat=5))
0.334306001663208

So powerlist2 is half as fast as the other two, which are very close.

For large n, #1 and #3 are still neck-and-neck:

py> n = 100
py> min(t1.repeat(number=100000, repeat=5))
3.6276791095733643
py> min(t3.repeat(number=100000, repeat=5))
3.58870792388916

which is what I would expect: the overhead of calling Python code will be
greater than the speed up from avoiding float multiplications. But long
integer unlimited-precision multiplications are slow. To really see the
advantage of avoiding multiplications using Horner's Method (powerlist1),
we need to use large integers and not floats.

py> x = 12345678*10000
py> n = 3
py> min(t1.repeat(number=100000, repeat=5))
0.2199108600616455
py> min(t3.repeat(number=100000, repeat=5))
0.551645040512085

As n becomes bigger, the advantage also increases:

py> n = 10
py> min(t1.repeat(number=100000, repeat=5))
0.736515998840332
py> min(t3.repeat(number=100000, repeat=5))
2.4837491512298584

In this case with n = 10, powerlist1 does 9 multiplications. But
powerlist3 makes ten calls to the ** operator. The number of
multiplications will depend on how cleverly exponentiation is
implemented: at worst, using a naive algorithm, there will be 36
multiplications. If the algorithm is a bit smarter, there will be 19
multiplications.

Either way, when the calculation is dominated by the cost of
multiplication, powerlist3 is between two and four times as expensive as
powerlist1.


--
Steven

alex23

unread,
Sep 16, 2012, 8:38:21 PM9/16/12
to
On Sep 15, 6:30 am, Terry Reedy <tjre...@udel.edu> wrote:
> > On 13Sep2012 18:58, alex23 <wuwe...@gmail.com> 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.
> > |
> > | 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.

Alexander Blinne

unread,
Sep 17, 2012, 4:39:17 AM9/17/12
to
On 16.09.2012 19:35, Steven D'Aprano wrote:
> On Sun, 16 Sep 2012 18:13:36 +0200, Alexander Blinne wrote:
>> def powerlist2(x,n):
>> if n==1:
>> return [1]
>> p = powerlist3(x,n-1)
>> p.append(p[-1]*x)
>> return p
>
> Is that a typo? I think you mean to make a recursive call to powerlist2,
> not a non-recursive call to powerlist3.

Yes, it is a typo. I originally tested 2 more versions, but tried to
change the numbering before posting. Bad idea :)

Jean-Michel Pichavant

unread,
Sep 17, 2012, 10:20:43 AM9/17/12
to pytho...@python.org


----- Original Message -----
> Jean-Michel Pichavant wrote:
[snip]
> One minor note, the style of decorator you are using loses the
> docstring
> (at least) of the original function. I would add the
> @functools.wraps(func)
> decorator inside your decorator.

Is there a way to not loose the function signature as well ?

help (t.api.spuAgc)
> spuAgc(self, iterations, backoffTarget, step) method of ...



But once decorated with this:

def stdApi(func):
@functools.wraps(func)
def inner(self, *args, **kwargs):
rsp = func(self, *args, **kwargs)
result = TncCmnResult()
result.returnCode = self._getReturnCode(rsp)
return result
return inner

help (t.api.spuAgc)
> t.api.spuAgc(self, *args, **kwargs) method of ....

Quite annoying :-/

JM

Thomas Rachel

unread,
Sep 18, 2012, 8:16:18 AM9/18/12
to
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

Neil Cerutti

unread,
Sep 18, 2012, 9:19:00 AM9/18/12
to
On 2012-09-14, Chris Angelico <ros...@gmail.com> wrote:
> But then again, who actually ever needs fibonacci numbers?

If it should happen that your question is not facetious:

http://en.wikipedia.org/wiki/Fibonacci_number#Applications

--
Neil Cerutti

Chris Angelico

unread,
Sep 18, 2012, 9:25:01 AM9/18/12
to pytho...@python.org
It wasn't entirely facetious. I know there are a few cases where
they're needed, but I think they're calculated far more often to
demonstrate algorithms than because you actually have use of them. :)

Though it's as well to mention these sorts of things now and then. I
remember one time writing up something or other, and my dad was
looking over my shoulder and asked me why I'd written a little
Pascal's Triangle generator. He didn't know that it had direct
application to whatever-it-was. And unfortunately I don't remember
what I was even writing at the time :)

ChrisA

88888 Dihedral

unread,
Sep 18, 2012, 11:14:42 AM9/18/12
to pytho...@python.org
Chris Angelico於 2012年9月18日星期二UTC+8下午9時25分04秒寫道:
I would suggest one should solve the Fibnaci(50000) first and fast in Python.

Then one can think about computing c(n,k) in Python for large n.


Then

88888 Dihedral

unread,
Sep 18, 2012, 11:14:42 AM9/18/12
to comp.lan...@googlegroups.com, pytho...@python.org
Chris Angelico於 2012年9月18日星期二UTC+8下午9時25分04秒寫道:

Dieter Maurer

unread,
Sep 18, 2012, 1:22:32 PM9/18/12
to pytho...@python.org
Jean-Michel Pichavant <jeanm...@sequans.com> writes:

> ----- Original Message -----
>> Jean-Michel Pichavant wrote:
> [snip]
>> One minor note, the style of decorator you are using loses the
>> docstring
>> (at least) of the original function. I would add the
>> @functools.wraps(func)
>> decorator inside your decorator.
>
> Is there a way to not loose the function signature as well ?

Look at the "decorator" module.

88888 Dihedral

unread,
Sep 18, 2012, 7:47:44 PM9/18/12
to pytho...@python.org
Terry Reedy於 2012年9月15日星期六UTC+8上午4時40分32秒寫道:
I'll give another example to show the decorators in python in
versions above 2.4 .

# a general function with the variable input : def fname( *argc, **argn)
# a deco is a mapping from an input funtion to another function

def deco( fn, *list_in, **dict_in): # use list_in and dict_in to modify fn
""" deco wrapper """ # deco.__doc__

#print list_in, dict_in, " in the deco"

def wrapper( fn, *argc, **argan): # to be returned as a function
# do things one wants before calling fn
result=fn(*argc, **argn) # call the original, save the result
# do things after calling fn
return result
# enhance the wrapper and get info of fn
wrapper.__doc__=fn.__doc__
# enhance wrapper with result, fn, list_in, dict_in
#....
return wrapper

def f1():
""" doc of f1"""
print "inside f1"

f2=deco(f1, 2,3,4,5,6, MSG="deco f1 to f2")

f2() # invoke the decorated function from f1


# For a deco maps a deco to another deco can be done similarly


88888 Dihedral

unread,
Sep 18, 2012, 7:47:44 PM9/18/12
to comp.lan...@googlegroups.com, pytho...@python.org

Trent Nelson

unread,
Sep 18, 2012, 10:20:04 PM9/18/12
to andrea crotti, python-list
On Thu, Sep 13, 2012 at 09:00:19AM -0700, andrea crotti wrote:
> 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).

FWIW, I gave a presentation on decorators to the New York Python
User Group back in 2008. Relevant blog post:

http://blogs.onresolve.com/?p=48

There's a link to the PowerPoint presentation I used in the first
paragraph. It's in .pptx format; let me know if you'd like it in
some other form.

Regards,

Trent.

andrea crotti

unread,
Sep 19, 2012, 12:42:23 PM9/19/12
to Trent Nelson, python-list
2012/9/19 Trent Nelson <tr...@snakebite.org>:
>
> FWIW, I gave a presentation on decorators to the New York Python
> User Group back in 2008. Relevant blog post:
>
> http://blogs.onresolve.com/?p=48
>
> There's a link to the PowerPoint presentation I used in the first
> paragraph. It's in .pptx format; let me know if you'd like it in
> some other form.
>
> Regards,
>
> Trent.


Ok thanks a lot, how long did it take for you to present that material?

Interesting the part about the learning process, I had a similar
experience, but probably skip this since I only have 30 minutes.

Another thing which I would skip or only explain how it works are
parametrized decorators, in the triple-def form they just look to ugly
to be worth the effort (but at least should be understood).

88888 Dihedral

unread,
Sep 19, 2012, 3:43:57 PM9/19/12
to Trent Nelson, python-list
andrea crotti於 2012年9月20日星期四UTC+8上午12時42分50秒寫道:
I think the decorator part is reasonable in testing and prototyping.

Every layor of some decorator just adds more overheads, therefore,
the syntax sugar of the symbol @ just reminds the programmer the fact.

Acctually writing better wrappers for non-trivial enhancements
to objects or functions should be practiced by professionals.

It is easy to import objects written by others in python.

It is also user responsible to test and enhance the objects
from others by decorators, the unittest module, or whatever suitable.


I love to play with functions with a varable representing the time
in writing computer games that emulate hundreds to thousands of
animated obects.









88888 Dihedral

unread,
Sep 19, 2012, 3:43:57 PM9/19/12
to comp.lan...@googlegroups.com, python-list
andrea crotti於 2012年9月20日星期四UTC+8上午12時42分50秒寫道:

andrea crotti

unread,
Sep 24, 2012, 11:42:50 AM9/24/12
to 88888 Dihedral, python-list, comp.lan...@googlegroups.com
For anyone interested, I already moved the slides on github
(https://github.com/AndreaCrotti/pyconuk2012_slides)
and for example the decorator slides will be generated from this:

https://raw.github.com/AndreaCrotti/pyconuk2012_slides/master/deco_context/deco.rst

Notice the literalinclude with :pyobject: which allows to include any
function or class automatically very nicely from external files ;)
0 new messages