Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #89608 > unrolled thread
| Started by | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| First post | 2015-04-30 09:07 +0200 |
| Last post | 2015-04-30 22:05 +0200 |
| Articles | 20 on this page of 37 — 12 participants |
Back to article view | Back to comp.lang.python
Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 09:07 +0200
Re: Python is not bad ;-) Ben Finney <ben+python@benfinney.id.au> - 2015-04-30 19:10 +1000
Re: Python is not bad ;-) Marko Rauhamaa <marko@pacujo.net> - 2015-04-30 13:16 +0300
Re: Python is not bad ;-) Chris Angelico <rosuav@gmail.com> - 2015-04-30 20:52 +1000
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 13:30 +0200
Re: Python is not bad ;-) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2015-05-01 17:03 +1000
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-05-01 09:47 +0200
Re: Python is not bad ;-) Christian Gollwitzer <auriocus@gmx.de> - 2015-05-01 19:56 +0200
Re: Python is not bad ;-) Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2015-05-02 19:44 +1200
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-05-02 10:26 +0200
Re: Python is not bad ;-) Marko Rauhamaa <marko@pacujo.net> - 2015-05-02 12:10 +0300
Re: Python is not bad ;-) Chris Angelico <rosuav@gmail.com> - 2015-05-02 19:25 +1000
Re: Python is not bad ;-) Marko Rauhamaa <marko@pacujo.net> - 2015-05-02 12:58 +0300
Re: Python is not bad ;-) Dave Angel <davea@davea.name> - 2015-05-02 06:22 -0400
Re: Python is not bad ;-) Chris Angelico <rosuav@gmail.com> - 2015-05-02 20:42 +1000
Re: Python is not bad ;-) Christian Gollwitzer <auriocus@gmx.de> - 2015-05-02 13:07 +0200
Re: Python is not bad ;-) Chris Angelico <rosuav@gmail.com> - 2015-05-02 21:21 +1000
Re: Python is not bad ;-) Christian Gollwitzer <auriocus@gmx.de> - 2015-05-02 13:32 +0200
Re: Python is not bad ;-) Marko Rauhamaa <marko@pacujo.net> - 2015-05-02 14:42 +0300
Re: Python is not bad ;-) Ian Kelly <ian.g.kelly@gmail.com> - 2015-05-02 09:45 -0600
Re: Python is not bad ;-) Chris Angelico <rosuav@gmail.com> - 2015-05-03 01:55 +1000
Re: Python is not bad ;-) Joonas Liik <liik.joonas@gmail.com> - 2015-05-02 16:50 +0300
Re: Python is not bad ;-) Joonas Liik <liik.joonas@gmail.com> - 2015-05-02 18:53 +0300
Re: Python is not bad ;-) Ian Kelly <ian.g.kelly@gmail.com> - 2015-05-02 11:00 -0600
Re: Python is not bad ;-) Ian Kelly <ian.g.kelly@gmail.com> - 2015-05-02 11:17 -0600
Re: Python is not bad ;-) Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-05-02 18:22 +0100
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-05-02 12:29 +0200
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-05-02 11:33 +0200
Re: Python is not bad ;-) Dave Angel <davea@davea.name> - 2015-05-02 06:35 -0400
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-05-02 13:12 +0200
Re: Python is not bad ;-) Ian Kelly <ian.g.kelly@gmail.com> - 2015-05-02 09:31 -0600
Re: Python is not bad ;-) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2015-05-01 15:56 +1000
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 13:10 +0200
Re: Python is not bad ;-) Michael Torrie <torriem@gmail.com> - 2015-04-30 08:03 -0600
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 18:11 +0200
Re: Python is not bad ;-) Christian Gollwitzer <auriocus@gmx.de> - 2015-04-30 19:59 +0200
Re: Python is not bad ;-) Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 22:05 +0200
Page 1 of 2 [1] 2 Next page →
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-04-30 09:07 +0200 |
| Subject | Python is not bad ;-) |
| Message-ID | <87mw1q9jqw.fsf@Equus.decebal.nl> |
I am coding with Python again. I like it that the code is concise and clear. But also that the performance is not bad. I wrote Lucky Numbers in Clojure and Python. When calling with 1E7 Clojure takes 12 seconds and Python 8 seconds. When calling it with 1E8 Clojure takes all 4/8 cores and gets an out of memory. Python takes one core and is finished after 888 seconds. When I call the Python version with 1E9 it is killed after 27 seconds. I get a message Killed and the error code is 137. Probably also an out of memory. When I do that the computer is freezed a few times. That is a little less nice. Does not happen with Clojure when it gets an out of memory. -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2015-04-30 19:10 +1000 |
| Message-ID | <mailman.121.1430385051.3680.python-list@python.org> |
| In reply to | #89608 |
Cecil Westerhof <Cecil@decebal.nl> writes:
> I am coding with Python again.
Great to know!
> I like it that the code is concise and clear. But also that the
> performance is not bad.
The former is a property of Python, which is a programming language. I
agree with your assessment :-)
The latter is not a property of Python; a programming language doesn't
have runtime performance. Rather, runtime performance is a property of
some specific *implementation* — that is, the runtime Python machine.
There are numerous Python runtimes, and they have different performance
characteristics on different hardware and operating systems.
<URL:https://wiki.python.org/moin/PythonImplementations>
You might be talking about performance on CPython. But you might not! I
don't know.
Have you looked at PyPy – Python implemented in Python – and compared
its performance?
--
\ “I went camping and borrowed a circus tent by mistake. I didn't |
`\ notice until I got it set up. People complained because they |
_o__) couldn't see the lake.” —Steven Wright |
Ben Finney
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-04-30 13:16 +0300 |
| Message-ID | <87383hj4zj.fsf@elektro.pacujo.net> |
| In reply to | #89614 |
Ben Finney <ben+python@benfinney.id.au>: > The latter is not a property of Python; a programming language doesn't > have runtime performance. Rather, runtime performance is a property of > some specific *implementation* — that is, the runtime Python machine. > > There are numerous Python runtimes, and they have different > performance characteristics on different hardware and operating > systems. Still, Python has features that defy effective optimization. Most notably, Python's dot notation translates into a hash table lookup -- or worse. I currently carry three clubs in my professional golf bag: bash, python and C. Java is a great programming language, but Python and C manage everything Java would be useful for. Marko
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-04-30 20:52 +1000 |
| Message-ID | <mailman.124.1430391126.3680.python-list@python.org> |
| In reply to | #89619 |
On Thu, Apr 30, 2015 at 8:16 PM, Marko Rauhamaa <marko@pacujo.net> wrote:
> Ben Finney <ben+python@benfinney.id.au>:
>
>> The latter is not a property of Python; a programming language doesn't
>> have runtime performance. Rather, runtime performance is a property of
>> some specific *implementation* — that is, the runtime Python machine.
>>
>> There are numerous Python runtimes, and they have different
>> performance characteristics on different hardware and operating
>> systems.
>
> Still, Python has features that defy effective optimization. Most
> notably, Python's dot notation translates into a hash table lookup -- or
> worse.
>
> I currently carry three clubs in my professional golf bag: bash, python
> and C. Java is a great programming language, but Python and C manage
> everything Java would be useful for.
(I carry a lot more clubs in my bag. The Ace of Clubs for me is Pike,
but Python comes in a close second; both are decently high
performance, quick to write code in, and come with extensive standard
libraries. Any bash script that grows to more than a page or so of
code usually finds itself rewritten in Python or Pike; C is mainly for
writing high level programming languages in.)
Most of the programs that I write spend their time on work far more
serious than looking up names in dictionaries. For instance, one of my
programs [1] shells out to avconv and sox to do a bunch of big file
conversions, doing its best to fill up my hard disk (eighty-odd gig of
intermediate files is a good start), and ultimately producing one
hefty video file. Another that I contribute heavily to [2] uses lame
to manipulate a bunch of .MP3 files and, ultimately, stream them down
an internet connection. A third [3] sleeps its entire life away,
either making network requests and waiting for the responses, or
outright sleep()ing until it needs to go do something again. If the
cost of run-time lookups of dotted names were to increase by an order
of magnitude, not one of them would materially change in performance.
Sure, you can do microbenchmarks that show that Python takes X times
longer to parse "x.y.z" than Java does, but if that's seriously
impacting your real-world code, what are you doing?
About the only time when Python performance makes a real difference is
on startup. Mercurial, for instance, has to be invoked, initialized,
and shut down, for every command. (That's why git tends to outdo it in
a lot of ways, thanks to being written mainly in C and Perl.) So yes,
there are efforts every now and then to cut the startup time, where
however-many modules all have to get imported and set up. In the most
micro of microbenchmarks, here's what it takes to do nothing in
several languages:
rosuav@sikorsky:~$ cat repeat.sh
for i in {1..100}; do $@; done
rosuav@sikorsky:~$ time bash repeat.sh pike -e ';'
real 0m8.504s
user 0m7.928s
sys 0m0.436s
rosuav@sikorsky:~$ time bash repeat.sh python3 -c pass
real 0m3.094s
user 0m2.400s
sys 0m0.424s
rosuav@sikorsky:~$ time bash repeat.sh python2 -c pass
real 0m1.843s
user 0m1.136s
sys 0m0.488s
rosuav@sikorsky:~$ echo 'int main() {return 0;}' |gcc -x c -
rosuav@sikorsky:~$ time bash repeat.sh ./a.out
real 0m0.076s
user 0m0.004s
sys 0m0.012s
So, yeah. Pike's a poor choice and C's superb if you want to start up
and shut down real fast. Great. But as soon as those figures get
dwarfed by real work, nothing else matters. It's a rare situation
where you really need to start a program in less than 0.085 seconds.
ChrisA
[1] https://github.com/Rosuav/FrozenOST
[2] https://github.com/MikeiLL/appension
[3] https://github.com/Rosuav/LetMeKnow
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-04-30 13:30 +0200 |
| Message-ID | <87d22lx38x.fsf@Equus.decebal.nl> |
| In reply to | #89619 |
Op Thursday 30 Apr 2015 12:16 CEST schreef Marko Rauhamaa:
> Ben Finney <ben+python@benfinney.id.au>:
>
>> The latter is not a property of Python; a programming language
>> doesn't have runtime performance. Rather, runtime performance is a
>> property of some specific *implementation* — that is, the runtime
>> Python machine.
>>
>> There are numerous Python runtimes, and they have different
>> performance characteristics on different hardware and operating
>> systems.
>
> Still, Python has features that defy effective optimization. Most
> notably, Python's dot notation translates into a hash table lookup
> -- or worse.
Tail recursion would nice to have also.
> I currently carry three clubs in my professional golf bag: bash,
I published a Bash library:
https://github.com/CecilWesterhof/BashLibrary
Maybe there is something useful in it for you. And if you need
something: let me know. No guarantees, but I could write it for you.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2015-05-01 17:03 +1000 |
| Message-ID | <55432557$0$12994$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #89624 |
On Thu, 30 Apr 2015 09:30 pm, Cecil Westerhof wrote: > Tail recursion would nice to have also. People coming from functional languages like Lisp and Haskell often say that, but how many recursive algorithms naturally take a tail-call form? Not that many. I suppose that it would be nice if Python let you optionally use tail-call optimization, but that might be tricky in practice. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-05-01 09:47 +0200 |
| Message-ID | <87618crb7q.fsf@Equus.decebal.nl> |
| In reply to | #89703 |
Op Friday 1 May 2015 09:03 CEST schreef Steven D'Aprano: > On Thu, 30 Apr 2015 09:30 pm, Cecil Westerhof wrote: > >> Tail recursion would nice to have also. > > People coming from functional languages like Lisp and Haskell often > say that, but how many recursive algorithms naturally take a > tail-call form? Not that many. When I was playing with Scala there where a few cases where tail recursion made a significant performance boost. Is some time ago, so I do not remember which. > I suppose that it would be nice if Python let you optionally use > tail-call optimization, but that might be tricky in practice. That is the difference between Scala and Clojure. Scala does it silently, while by Clojure you have to say you want it. When a chance breaks tail recursion Scala just compiles, but your code becomes slower, Clojure does not compile. I prefer the Clojure variant. -- Cecil Westerhof Senior Software Engineer LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Christian Gollwitzer <auriocus@gmx.de> |
|---|---|
| Date | 2015-05-01 19:56 +0200 |
| Message-ID | <mi0elj$ujt$1@dont-email.me> |
| In reply to | #89703 |
Am 01.05.15 um 09:03 schrieb Steven D'Aprano: > On Thu, 30 Apr 2015 09:30 pm, Cecil Westerhof wrote: > >> Tail recursion would nice to have also. > > People coming from functional languages like Lisp and Haskell often say > that, but how many recursive algorithms naturally take a tail-call form? > Not that many. That is because tailcall optimization is used in functional languages mainly as a replacement for loops. IOW, in non-functional languages you can simply use an infinite loop to do the same (in most cases). > I suppose that it would be nice if Python let you optionally use tail-call > optimization, but that might be tricky in practice. > In Tcl 8.6 there is an explicit "tailcall something" command which calls something without creating a new stack frame, i.e. it returns to the caller after something returns. Useful sometimes, but more a micro-optimization than a vital feature. Christian
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2015-05-02 19:44 +1200 |
| Message-ID | <cqjditFd6n5U1@mid.individual.net> |
| In reply to | #89703 |
Steven D'Aprano wrote: > People coming from functional languages like Lisp and Haskell often say > that, but how many recursive algorithms naturally take a tail-call form? > Not that many. And the ones that do tend to be the ones that are better expressed iteratively in Python. So Python doesn't really need tail call optimisation. Also, Guido has said that he doesn't like it, because of the detrimental effect it has on stack tracebacks. -- Greg
[toc] | [prev] | [next] | [standalone]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-05-02 10:26 +0200 |
| Message-ID | <87383fo062.fsf@Equus.decebal.nl> |
| In reply to | #89703 |
Op Friday 1 May 2015 09:03 CEST schreef Steven D'Aprano:
> On Thu, 30 Apr 2015 09:30 pm, Cecil Westerhof wrote:
>
>> Tail recursion would nice to have also.
>
> People coming from functional languages like Lisp and Haskell often
> say that, but how many recursive algorithms naturally take a
> tail-call form? Not that many.
One example:
def factorial(x, y = 1):
return y if x == 1 else factorial(x - 1, x * y)
def factorial_iterative(x):
result = 1
for i in range(2, x + 1):
result *= i
return result
Executing factorial(985) 100.000 times takes 54 seconds.
While executing factorial_iterative(985) takes 34 seconds.
Also you can not call factorial with a value that is much bigger
because of recursion depth. You can call factorial_iterative with
1.000.000.
I made also a version that simulates tail recursion:
def factorial_tail_recursion(x):
y = 1
while True:
if x == 1:
return y
y *= x
x -= 1
This is that a lot less efficient as the iterative version. It takes 43
seconds. But it is a lot better as the normal recursive version: about
25%. The iterative version is about 25% more efficient as the tail
recursion version.
With larger values it decreases. Calculating onetime for 5.000.000
takes 117 and 131 seconds. Just 10% faster.
That is mostly because the tail recursion version starts multiplying
at the high end. I wrote a second version:
def factorial_tail_recursion2(x):
y = 1
z = 1
while True:
if x == z:
return y
y *= z
z += 1
This has almost the performance of the iterative version: 34 and 121
seconds.
So I made a new recursive version:
def factorial_recursive(x, y = 1, z = 1):
return y if x == z else factorial_recursive(x, x * y, z + 1)
But this take almost the same tame as the other. Probably the
recursive calls are more important as the multiplications.
I find factorial a lot cleaner code as factorial_iterative, so here
tail recursion would be beneficial.
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-05-02 12:10 +0300 |
| Message-ID | <87egmzl4yr.fsf@elektro.pacujo.net> |
| In reply to | #89747 |
Cecil Westerhof <Cecil@decebal.nl>: > I find factorial a lot cleaner code as factorial_iterative, so here > tail recursion would be beneficial. I would just call math.factorial() and be done with it. Note: Scheme is my favorite language and I use tail recursion all the time. I also think eliminating tail recursion is such a low-hanging fruit that even CPython should just pick it. However, I wouldn't use the fibonacci sequence to justify anything at all about a programming language. It's not about performance (that's rarely a very useful argument when it comes to Python). It's only that every now and then a very natural tail recursion crops up and it's just silly to have to refactor perfectly good code because of a stack overflow. Marko
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-05-02 19:25 +1000 |
| Message-ID | <mailman.4.1430558719.12865.python-list@python.org> |
| In reply to | #89749 |
On Sat, May 2, 2015 at 7:10 PM, Marko Rauhamaa <marko@pacujo.net> wrote: > Note: Scheme is my favorite language and I use tail recursion all the > time. I also think eliminating tail recursion is such a low-hanging > fruit that even CPython should just pick it. However, I wouldn't use the > fibonacci sequence to justify anything at all about a programming > language. Actually, it isn't such low-hanging fruit. As has been mentioned in this thread already, Guido is against anything that disrupts tracebacks, and optimizing tail recursion while maintaining traceback integrity is rather harder. In the situations where it really is simple, you can always make the change in your own code anyway. Often, the process of converting recursion into tail recursion warps the code to the point where it's abusing recursion to implement iteration anyway, so just make it iterative. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-05-02 12:58 +0300 |
| Message-ID | <87a8xnl2r6.fsf@elektro.pacujo.net> |
| In reply to | #89753 |
Chris Angelico <rosuav@gmail.com>: > Guido is against anything that disrupts tracebacks, and optimizing > tail recursion while maintaining traceback integrity is rather harder. Tail recursion could be suppressed during debugging. Optimized code can play all kinds of non-obvious tricks with the execution frame. > In the situations where it really is simple, you can always make the > change in your own code anyway. Often, the process of converting > recursion into tail recursion warps the code to the point where it's > abusing recursion to implement iteration anyway, so just make it > iterative. While you shouldn't actively replace Python iteration with recursion, I strongly disagree that naturally occurring tail recursion is abuse or should be avoided in any manner. Marko
[toc] | [prev] | [next] | [standalone]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2015-05-02 06:22 -0400 |
| Message-ID | <mailman.5.1430562152.12865.python-list@python.org> |
| In reply to | #89754 |
On 05/02/2015 05:58 AM, Marko Rauhamaa wrote:
> Chris Angelico <rosuav@gmail.com>:
>
>> Guido is against anything that disrupts tracebacks, and optimizing
>> tail recursion while maintaining traceback integrity is rather harder.
>
> Tail recursion could be suppressed during debugging. Optimized code can
> play all kinds of non-obvious tricks with the execution frame.
>
>> In the situations where it really is simple, you can always make the
>> change in your own code anyway. Often, the process of converting
>> recursion into tail recursion warps the code to the point where it's
>> abusing recursion to implement iteration anyway, so just make it
>> iterative.
>
> While you shouldn't actively replace Python iteration with recursion, I
> strongly disagree that naturally occurring tail recursion is abuse or
> should be avoided in any manner.
>
When you strongly disagree, make sure you're disagreeing with what Chris
actually said. The key phrase in his message was
"converting recursion into tail recursion"
NOT "converting iteration into recursion"
and NOT "naturally occurring tail recursion"
--
DaveA
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-05-02 20:42 +1000 |
| Message-ID | <mailman.7.1430563337.12865.python-list@python.org> |
| In reply to | #89754 |
On Sat, May 2, 2015 at 8:22 PM, Dave Angel <davea@davea.name> wrote:
> On 05/02/2015 05:58 AM, Marko Rauhamaa wrote:
>>
>> Chris Angelico <rosuav@gmail.com>:
>>
>>> Guido is against anything that disrupts tracebacks, and optimizing
>>> tail recursion while maintaining traceback integrity is rather harder.
>>
>>
>> Tail recursion could be suppressed during debugging. Optimized code can
>> play all kinds of non-obvious tricks with the execution frame.
>>
>>> In the situations where it really is simple, you can always make the
>>> change in your own code anyway. Often, the process of converting
>>> recursion into tail recursion warps the code to the point where it's
>>> abusing recursion to implement iteration anyway, so just make it
>>> iterative.
>>
>>
>> While you shouldn't actively replace Python iteration with recursion, I
>> strongly disagree that naturally occurring tail recursion is abuse or
>> should be avoided in any manner.
>>
>
> When you strongly disagree, make sure you're disagreeing with what Chris
> actually said. The key phrase in his message was
> "converting recursion into tail recursion"
>
> NOT "converting iteration into recursion"
> and NOT "naturally occurring tail recursion"
Indeed. I'll clarify my statement.
When a function needs to do further actions after the tail call, the
usual solution is to carry the information through parameters.
def stupid_sum_iter(x):
"""Calculate sum(range(x+1))"""
tot = 0
while x:
tot += x
x -= 1
return tot
def stupid_sum_recur(x):
return x and x + stupid_sum_recur(x - 1)
def stupid_sum_tail_recur(x, tot=0):
if not x: return tot
return stupid_sum_tail_recur(x - 1, tot + x)
Converting the recursive form into optimizable tail recursion requires
an accumulator parameter, which means it's virtually the same as the
iterative version. Naturally-occurring tail recursion does exist, but
it's far from all cases of recursion.
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Christian Gollwitzer <auriocus@gmx.de> |
|---|---|
| Date | 2015-05-02 13:07 +0200 |
| Message-ID | <mi2b49$pip$1@dont-email.me> |
| In reply to | #89754 |
Am 02.05.15 um 11:58 schrieb Marko Rauhamaa: > Chris Angelico <rosuav@gmail.com>: > >> Guido is against anything that disrupts tracebacks, and optimizing >> tail recursion while maintaining traceback integrity is rather harder. > > Tail recursion could be suppressed during debugging. Optimized code can > play all kinds of non-obvious tricks with the execution frame. > >> In the situations where it really is simple, you can always make the >> change in your own code anyway. Often, the process of converting >> recursion into tail recursion warps the code to the point where it's >> abusing recursion to implement iteration anyway, so just make it >> iterative. > > While you shouldn't actively replace Python iteration with recursion, I > strongly disagree that naturally occurring tail recursion is abuse or > should be avoided in any manner. Could you show me an example of naturally occuring tail recursion? I can't think of any. Or is it maybe one involving mutual recursion? I need to add, I grew up with imperative programming, and as such got recursion as the solution to problems that are too complex for iteration, i.e. tree traversal and such, and exactly these are never tail-recursive. Christian
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-05-02 21:21 +1000 |
| Message-ID | <mailman.9.1430565706.12865.python-list@python.org> |
| In reply to | #89762 |
On Sat, May 2, 2015 at 9:07 PM, Christian Gollwitzer <auriocus@gmx.de> wrote:
> I need to add, I grew up with imperative programming, and as such got
> recursion as the solution to problems that are too complex for iteration,
> i.e. tree traversal and such, and exactly these are never tail-recursive.
Tree traversal can be forking-recursive:
def walk(func):
if self.left and self.left.walk(func): return 1
if func(self.payload): return 1
if self.right: return self.right.walk(func)
The left walk is non-tail-recursive, but the right walk is. This
particular style looks rather less clean with iteration:
def walk(func):
while True:
if self.left and self.left.walk(func): return 1
if func(self.payload): return 1
if not self.right: break
self = self.right
I'd call this an example of fairly natural tail recursion.
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Christian Gollwitzer <auriocus@gmx.de> |
|---|---|
| Date | 2015-05-02 13:32 +0200 |
| Message-ID | <mi2cjc$uq2$1@dont-email.me> |
| In reply to | #89764 |
Am 02.05.15 um 13:21 schrieb Chris Angelico: > On Sat, May 2, 2015 at 9:07 PM, Christian Gollwitzer <auriocus@gmx.de> wrote: >> I need to add, I grew up with imperative programming, and as such got >> recursion as the solution to problems that are too complex for iteration, >> i.e. tree traversal and such, and exactly these are never tail-recursive. > > Tree traversal can be forking-recursive: > > def walk(func): > if self.left and self.left.walk(func): return 1 > if func(self.payload): return 1 > if self.right: return self.right.walk(func) > > The left walk is non-tail-recursive, but the right walk is. This > particular style looks rather less clean with iteration: Accepted. In case your tree is heavily imbalanced, i.e. it is a list pretending to be a tree, the tail-recursion can cut down the memory usage significantly. It does not help, though, in the general case of a balanced tree or if the tree leans to the left side. That's why I still think it is a microoptimization, which helps only in some specific cases. Christian
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-05-02 14:42 +0300 |
| Message-ID | <87383fkxy0.fsf@elektro.pacujo.net> |
| In reply to | #89766 |
Christian Gollwitzer <auriocus@gmx.de>: > That's why I still think it is a microoptimization, which helps only > in some specific cases. It isn't done for performance. It's done to avoid a stack overflow exception. Marko
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-05-02 09:45 -0600 |
| Message-ID | <mailman.13.1430581560.12865.python-list@python.org> |
| In reply to | #89767 |
On Sat, May 2, 2015 at 5:42 AM, Marko Rauhamaa <marko@pacujo.net> wrote: > Christian Gollwitzer <auriocus@gmx.de>: > >> That's why I still think it is a microoptimization, which helps only >> in some specific cases. > > It isn't done for performance. It's done to avoid a stack overflow > exception. If your tree is balanced, then the number of items you would need to have to get a stack overflow exception would be approximately 2 ** 1000, which you can't possibly hope to fit into memory. If your tree is unbalanced and you're getting a stack overflow exception, then maybe you should think about balancing it.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.python
csiph-web