Basic question about speed/coding style/memory

Discussion in 'Python' started by Jan Riechers, Jul 21, 2012.

  1. Jan Riechers

    Jan Riechers Guest

    Hello Pythonlist,

    I have one very basic question about speed,memory friendly coding, and
    coding style of the following easy "if"-statement in Python 2.7, but Im
    sure its also the same in Python 3.x

    Block
    #----------------------------------
    if statemente_true:
    doSomething()
    else:
    doSomethingElseInstead()

    #----------------------------------

    versus this block:
    #----------------------------------
    if statement_true:
    doSomething()
    return

    doSomethingElseInstead()

    #----------------------------------


    I understand the first pattern that I tell the interpreter to do:
    Check if the conditional is true, run "doSomething()" else go inside the
    else block and "doSomethingElseInstead()".

    while the 2nd does only checks:
    doSomething() if statement_true, if not, just go directly to
    "doSomethingElseInstead()


    Now, very briefly, what is the better way to proceed in terms of
    execution speed, readability, coding style?
    Letting out the fact that, in order to prevent
    "doSomethingElseInstead"-Block to execute, a return has to provided.

    Thank you for reading and hope someone brings light into that.

    Your fellow python programmer
    Jan
     
    Jan Riechers, Jul 21, 2012
    #1
    1. Advertising

  2. On Sat, 21 Jul 2012 10:33:27 +0300, Jan Riechers wrote:

    > Hello Pythonlist,
    >
    > I have one very basic question about speed,memory friendly coding, and
    > coding style of the following easy "if"-statement in Python 2.7, but Im
    > sure its also the same in Python 3.x


    I assume that the following is meant to be inside a function, otherwise
    the return in the second example is illegal.

    But in general, you're worrying too much about trivia. One way or the
    other, any speed difference will be trivial. Write whatever style reads
    and writes most naturally, and only worry about what's faster where it
    actually counts.

    To give it an analogy that might be clear, this question is not too far
    from worrying about whether your car will be faster with the radio aerial
    up or down. Yes, technically the car will be slower with the aerial up,
    due to air resistance, but you'd have a job measuring it, and it makes no
    difference whether you are zooming down the highway at 120mph or stuck in
    traffic crawling along at 5mph.


    Here's a minimal example:


    def with_else(x):
    if x:
    a = x
    else:
    a = x+1
    return a


    def without_else(x):
    if x:
    a = x
    return a
    a = x+1
    return a


    Notice that I try to make each function do the same amount of work, so
    that we're seeing only the difference between "else" vs "no else".

    Now let's test the speed difference with Python 2.7. Because this is
    timing small code snippets, we should use the timeit module to time the
    code:

    from timeit import Timer
    setup = "from __main__ import with_else, without_else"
    t1 = Timer("for i in (0, 1): result = with_else(i)", setup)
    t2 = Timer("for i in (0, 1): result = without_else(i)", setup)

    Each snippet calls the function twice, once to take the if branch, then
    to take the else branch.

    Now we time how long it takes to run each code snippet 1000000 times. We
    do that six times each, and print the best (lowest) speed:

    py> min(t1.repeat(repeat=6))
    0.9761919975280762
    py> min(t2.repeat(repeat=6))
    0.9494419097900391

    So there is approximately 0.03 second difference per TWO MILLION
    if...else blocks, or about 15 nanoseconds each. This is highly unlikely
    to be the bottleneck in your code. Assuming the difference is real, and
    not just measurement error, the difference is insignificant.

    So, don't worry about which is faster. Write whichever is more natural,
    easier to read and write.


    > Block
    > #----------------------------------
    > if statemente_true:
    > doSomething()
    > else:
    > doSomethingElseInstead()


    This style is especially recommended when the two clauses are equal in
    importance.


    > versus this block:
    > #----------------------------------
    > if statement_true:
    > doSomething()
    > return
    > doSomethingElseInstead()


    This style is especially recommended when the doSomethingElseInstead()
    block is the "normal" procedure, and the doSomething() block is a special
    case. Not necessarily rare, but nevertheless special in some sense.

    Of course, the decision as to which is the "special" case and which is
    the "normal" case is often entirely arbitrary.



    --
    Steven
     
    Steven D'Aprano, Jul 21, 2012
    #2
    1. Advertising

  3. Jan Riechers

    Jan Riechers Guest

    On 21.07.2012 12:06, Steven D'Aprano wrote:
    >
    > But in general, you're worrying too much about trivia. One way or the
    > other, any speed difference will be trivial. Write whatever style reads
    > and writes most naturally, and only worry about what's faster where it
    > actually counts.
    >


    >
    > Notice that I try to make each function do the same amount of work, so
    > that we're seeing only the difference between "else" vs "no else".
    >
    > Now let's test the speed difference with Python 2.7. Because this is
    > timing small code snippets, we should use the timeit module to time the
    > code:
    >
    > from timeit import Timer
    > setup = "from __main__ import with_else, without_else"
    > t1 = Timer("for i in (0, 1): result = with_else(i)", setup)
    > t2 = Timer("for i in (0, 1): result = without_else(i)", setup)
    >
    > Each snippet calls the function twice, once to take the if branch, then
    > to take the else branch.
    >
    > Now we time how long it takes to run each code snippet 1000000 times. We
    > do that six times each, and print the best (lowest) speed:
    >
    > py> min(t1.repeat(repeat=6))
    > 0.9761919975280762
    > py> min(t2.repeat(repeat=6))
    > 0.9494419097900391
    >
    > So there is approximately 0.03 second difference per TWO MILLION
    > if...else blocks, or about 15 nanoseconds each. This is highly unlikely
    > to be the bottleneck in your code. Assuming the difference is real, and
    > not just measurement error, the difference is insignificant.
    >
    > So, don't worry about which is faster. Write whichever is more natural,
    > easier to read and write.
    >
    >


    Hello Steven,

    very nice example and thank you very much for also for the Timeit test!
    Actually it confirms my assumption in some way:

    [SNIP myself]
    So if there is some overhead in some fashion in case we don't offer the
    else, assuming the interpreter has to exit the evaluation of the
    "if"-statement clause and return to a "normal parsing code"-state
    outside the if statement itself.
    [SNAP]

    Without having looked at Andrew's bytecode excecution hint, using the
    dis module, to see how the interpreter handles the task on lower level.

    But fare enough for me :)

    But I agree, the return in my example is misleading and it would be
    illegal outside of a function call. I just added it to make clear that
    the fellow code below the return should not be executed in comparison to
    the 2nd example.

    Thank you very much
    Jan
     
    Jan Riechers, Jul 21, 2012
    #3
  4. Jan Riechers wrote:

    > I have one very basic question about speed,memory friendly coding, and
    > coding style of the following easy "if"-statement in Python 2.7, but Im
    > sure its also the same in Python 3.x
    >
    > Block
    > #----------------------------------
    > if statemente_true:
    > doSomething()
    > else:
    > doSomethingElseInstead()
    >
    > #----------------------------------
    >
    > versus this block:
    > #----------------------------------
    > if statement_true:
    > doSomething()
    > return
    >
    > doSomethingElseInstead()
    >
    > #----------------------------------
    >
    >
    > I understand the first pattern that I tell the interpreter to do:


    A common misconception. As a writer of Python source code, (usually) you
    never tell the (CPython) interpreter anything (but to start working on the
    source code). Python source code is automatically *compiled* into bytecode
    by the (CPython) interpreter, and that bytecode is executed by a virtual
    machine.¹ So at most, you are telling that virtual machine to do something,
    through the bytecode created from your source code.

    > Check if the conditional is true, run "doSomething()" else go inside the
    > else block and "doSomethingElseInstead()".
    >
    > while the 2nd does only checks:
    > doSomething() if statement_true, if not, just go directly to
    > "doSomethingElseInstead()
    >
    >
    > Now, very briefly, what is the better way to proceed in terms of
    > execution speed, readability, coding style?


    Since this is comp.lang.python, you just need to check against the Zen of
    Python to know what you should do ;-)

    <http://www.python.org/dev/peps/pep-0020/>

    For me, this boils down in this case to the common recommendation "return
    early, return often" as "explicit is better than implicit" and "readability
    counts". If there is nothing else than the `else' block in the function,
    there is no use for you to continue in the function, so you should return
    explicitly at this point.

    On the other hand, if you can *avoid repeating code* in each branch by _not_
    returning in the first branch, you should do that instead ("practicality
    beats purity").

    HTH

    _____
    ¹ This is not unlike in other so-called "scripting languages"; although for
    reasons that escape me, the software that compiles the source code – the
    compiler – is called the (C)Python *interpreter*, even in
    <http://docs.python.org/faq/general.html>.
    --
    PointedEars

    Please do not Cc: me. / Bitte keine Kopien per E-Mail.
     
    Thomas 'PointedEars' Lahn, Jul 21, 2012
    #4
  5. On Sat, Jul 21, 2012 at 5:06 AM, Steven D'Aprano
    <> wrote:
    > So there is approximately 0.03 second difference per TWO MILLION
    > if...else blocks, or about 15 nanoseconds each. This is highly unlikely
    > to be the bottleneck in your code. Assuming the difference is real, and
    > not just measurement error, the difference is insignificant.


    It's probably real. For if-else, the true case needs to make a jump
    before it returns, but for if-return, there's no jump and the return
    is inlined.

    -- Devin

    > So, don't worry about which is faster. Write whichever is more natural,
    > easier to read and write.


    The most important advice. Even when it's a larger difference! :)

    -- Devin
     
    Devin Jeanpierre, Jul 22, 2012
    #5
  6. Jan Riechersæ–¼ 2012å¹´7月21日星期六UTC+8下åˆ3時33分27秒寫é“:
    > Hello Pythonlist,
    >
    > I have one very basic question about speed,memory friendly coding, and
    > coding style of the following easy &quot;if&quot;-statement in Python 2.7, but Im
    > sure its also the same in Python 3.x
    >
    > Block
    > #----------------------------------
    > if statemente_true:


    if an evaluated expression result is non-zero, then


    > doSomething()


    > else:

    # execute this block if the expression evaluated as zero

    > doSomethingElseInstead()
    >
    > #----------------------------------
    >
    > versus this block:
    > #----------------------------------
    > if statement_true:
    > doSomething()
    > return
    >
    > doSomethingElseInstead()
    >
    > #----------------------------------
    >
    >
    > I understand the first pattern that I tell the interpreter to do:
    > Check if the conditional is true, run &quot;doSomething()&quot; else go inside the
    > else block and &quot;doSomethingElseInstead()&quot;.
    >
    > while the 2nd does only checks:
    > doSomething() if statement_true, if not, just go directly to
    > &quot;doSomethingElseInstead()
    >
    >
    > Now, very briefly, what is the better way to proceed in terms of
    > execution speed, readability, coding style?
    > Letting out the fact that, in order to prevent
    > &quot;doSomethingElseInstead&quot;-Block to execute, a return has to provided.
    >
    > Thank you for reading and hope someone brings light into that.
    >
    > Your fellow python programmer
    > Jan


    Well, the C-style branching is inherited in python.

    Expressions and statements are different.
     
    88888 Dihedral, Jul 23, 2012
    #6
  7. Jan Riechersæ–¼ 2012å¹´7月21日星期六UTC+8下åˆ3時33分27秒寫é“:
    > Hello Pythonlist,
    >
    > I have one very basic question about speed,memory friendly coding, and
    > coding style of the following easy &quot;if&quot;-statement in Python 2.7, but Im
    > sure its also the same in Python 3.x
    >
    > Block
    > #----------------------------------
    > if statemente_true:


    if an evaluated expression result is non-zero, then


    > doSomething()


    > else:

    # execute this block if the expression evaluated as zero

    > doSomethingElseInstead()
    >
    > #----------------------------------
    >
    > versus this block:
    > #----------------------------------
    > if statement_true:
    > doSomething()
    > return
    >
    > doSomethingElseInstead()
    >
    > #----------------------------------
    >
    >
    > I understand the first pattern that I tell the interpreter to do:
    > Check if the conditional is true, run &quot;doSomething()&quot; else go inside the
    > else block and &quot;doSomethingElseInstead()&quot;.
    >
    > while the 2nd does only checks:
    > doSomething() if statement_true, if not, just go directly to
    > &quot;doSomethingElseInstead()
    >
    >
    > Now, very briefly, what is the better way to proceed in terms of
    > execution speed, readability, coding style?
    > Letting out the fact that, in order to prevent
    > &quot;doSomethingElseInstead&quot;-Block to execute, a return has to provided.
    >
    > Thank you for reading and hope someone brings light into that.
    >
    > Your fellow python programmer
    > Jan


    Well, the C-style branching is inherited in python.

    Expressions and statements are different.
     
    88888 Dihedral, Jul 23, 2012
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. calmar
    Replies:
    11
    Views:
    909
    calmar
    Feb 21, 2006
  2. Andrew Berg
    Replies:
    0
    Views:
    108
    Andrew Berg
    Jul 21, 2012
  3. Jan Riechers
    Replies:
    0
    Views:
    112
    Jan Riechers
    Jul 21, 2012
  4. Chris Angelico
    Replies:
    2
    Views:
    154
    88888 Dihedral
    Jul 23, 2012
  5. Andrew Berg
    Replies:
    0
    Views:
    120
    Andrew Berg
    Jul 21, 2012
Loading...

Share This Page