Counting iterations

Discussion in 'Python' started by Derek Basch, Apr 8, 2005.

  1. Derek Basch

    Derek Basch Guest

    Is there a better way to count iterations that this?:

    pets = 0
    for i in pets:
    pets += 1
    print "pet" + "#" + pets

    Thanks,
    Derek Basch
    Derek Basch, Apr 8, 2005
    #1
    1. Advertising

  2. Derek Basch wrote:
    > Is there a better way to count iterations that this?:
    >
    > pets = 0
    > for i in pets:
    > pets += 1
    > print "pet" + "#" + pets


    for i, pet in enumerate(pets):
    print 'pet#%i' % (i + 1)

    STeVe
    Steven Bethard, Apr 8, 2005
    #2
    1. Advertising

  3. Derek Basch

    Will McGugan Guest

    Derek Basch wrote:
    > Is there a better way to count iterations that this?:
    >
    > pets = 0
    > for i in pets:
    > pets += 1
    > print "pet" + "#" + pets
    >


    You can use 'enumerate' to get the index, but the code above wont work -
    you are trying to iterate over a non-sequence.

    Will McGugan

    --
    "".join( [ {'@':'@','.':'.'}.get(c,None) or chr(97+((ord(c)-97)+13)%26)
    for c in "" ] )
    Will McGugan, Apr 8, 2005
    #3
  4. Derek Basch

    Derek Basch Guest

    ooops you are right. Should have been:

    pets = ["cat", "dog", "bird"]
    num_pets = 0
    for i in pets:
    num_pets += 1
    print "pet" + "#" + num_pets

    That's the problem with one offs. I don't read them :).
    Derek Basch, Apr 8, 2005
    #4
  5. Derek Basch wrote:

    > ooops you are right. Should have been:
    >
    > pets = ["cat", "dog", "bird"]
    > num_pets = 0
    > for i in pets:
    > num_pets += 1
    > print "pet" + "#" + num_pets


    Traceback (most recent call last):
    File "example.py", line 5, in ?
    print "pet" + "#" + num_pets
    TypeError: cannot concatenate 'str' and 'int' objects

    </F>
    Fredrik Lundh, Apr 9, 2005
    #5
  6. Derek Basch

    runes Guest

    You should avoid the "a" + "b" + "c" -kind of concatenation. As strings
    at immutable in Python you actually makes copies all the time and it's
    slow!

    The alternative used in Steven Bethard's example is preferable.
    runes, Apr 9, 2005
    #6
  7. Derek Basch

    Andrew Dalke Guest

    runes wrote:
    > You should avoid the "a" + "b" + "c" -kind of concatenation. As strings
    > at immutable in Python you actually makes copies all the time and it's
    > slow!


    The OP wrote

    print "pet" + "#" + num_pets

    (properly str(num_pets) )

    You recommended the "alternative used in Steven Bethard's example"

    print 'pet#%i' % (i + 1)

    because "it's slow". I disagree, it isn't for this code.
    It's comparable in performance to interpolation and most
    of the time is spent in converting int -> string. Indeed
    if the object to be merged is a string then the addition
    version is faster than interpolation.

    Here's the details.

    The string concatenation performance that you're
    talking about doesn't hit until there are multiple
    appends to the same string, where "multiple" is rather
    more than 2. The advice usually applies to things like

    text = ""
    for line in open(filename, "U"):
    text += line

    which is much slower than, say
    lines = []
    for line in open(filename, "U")
    lines.append(line)
    text = "".join(lines)

    or the more modern
    text = "".join(open(filename, "U"))

    to say nothing of
    text = open(filename, "U").read() :)

    Anyway, to get back to the example at hand,
    consider what happens in

    "pet#%i" % (i+1)

    (NOTE: most times that's written %d instead of %i)

    The run-time needs to parse the format string
    and construct a new string from the components.
    Internally it does the same thing as

    "pet#" + str(i+1)

    except that it's done at the C level instead
    Python and the implementation overallocates
    100 bytes so there isn't an extra allocation
    in cases like this.

    Personally I would expect the "%" code to be
    about the same performance as the "+" code.


    Of course the real test is in the timing.
    Here's what I tried. NOTE: I reformatted by
    hand to make it more readable. Line breaks and
    the \ continuation character may have introduced
    bugs.

    First, the original code along with the 'str()'
    correction.

    % python /usr/local/lib/python2.3/timeit.py -s \
    'pets = ["cat", "dog", "bird"]' \
    'num_pets=0' 'for pet in pets:' \
    ' num_pets += 1' \
    ' s="pet" + "#" + str(num_pets)'
    100000 loops, best of 3:
    14.5 usec per loop


    There's no need for the "pet" + "#" so I'll
    turn that into "pet#"

    % python /usr/local/lib/python2.3/timeit.py -s \
    'pets = ["cat", "dog", "bird"]' \
    'num_pets=0' \
    'for pet in pets:' \
    ' num_pets += 1' \
    ' s="pet#" + str(num_pets)'
    100000 loops, best of 3: 12.8 usec per loop

    That's 1.3 extra usecs.

    By comparison here's the "%" version.

    % python /usr/local/lib/python2.3/timeit.py -s \
    'pets = ["cat", "dog", "bird"]'\
    'num_pets=0' \
    'for pet in pets:' \
    ' num_pets += 1' \
    ' s="pet#%s" % num_pets'
    100000 loops, best of 3: 10.8 usec per loop

    I'm surprised that it's that much faster - a
    good 2 microseconds and that isn't the only
    code in that loop.

    But both the "%" and "+" solutions need to
    convert the number into a string. If I
    use an existing string I find

    % python /usr/local/lib/python2.3/timeit.py -s \
    'pets = ["cat", "dog", "bird"]' \
    'num_pets=0' \
    'for pet in pets:' \
    ' num_pets += 1' \
    ' s="pet#" + pet'
    100000 loops, best of 3: 4.62 usec per loop

    So really most of the time - about 8 usec - is
    spent in converting int -> string and the
    hit for string concatenation or interpolation
    isn't as big a problem.

    Compare with the string interpolation form
    of the last version

    % python /usr/local/lib/python2.3/timeit.py -s \
    'pets = ["cat", "dog", "bird"]' \
    'num_pets=0' 'for pet in pets:' \
    ' num_pets += 1' \
    ' s="pet#%s" % pet' \
    100000 loops, best of 3: 7.55 usec per loop


    In this case you can see that the % version is
    slower (by 2usec) than the + version.

    I therefore disagree with the idea that simple
    string concatenation is always to be eschewed
    over string interpolation.

    Andrew
    Andrew Dalke, Apr 9, 2005
    #7
  8. Andrew Dalke wrote:
    > "pet#%i" % (i+1)
    >
    > (NOTE: most times that's written %d instead of %i)


    Any reason to prefer %d over %i? The library reference seems to suggest
    that they're the same thing[1]. I've typically used %i since I can
    remember it from the int type, like I can remember %f from the float
    type. Is there any reason not to?

    STeVe

    [1] http://docs.python.org/lib/typesseq-strings.html
    Steven Bethard, Apr 10, 2005
    #8
  9. Derek Basch

    runes Guest

    runes, Apr 10, 2005
    #9
  10. Derek Basch

    Derek Basch Guest

    Interesting stuff Andrew. I do generally avoid string concantination
    for the reason listed in the Python Performance Tips but your analysis
    kinda puts that in question. Such a dense discussion for me just trying
    to find the enumerate() function :). I guess that is why the python
    list is so great. You guys always rip my code apart and correct my
    style. Even if it is just a stupid one off example.

    Thanks everyone,
    Derek Basch
    Derek Basch, Apr 10, 2005
    #10
  11. Derek Basch

    Terry Reedy Guest

    "runes" <> wrote in message
    news:...
    >
    > [Andrew Dalke]
    >> I therefore disagree with the idea that simple
    >> string concatenation is always to be eschewed
    >> over string interpolation.


    String cat (+) is fine for joining a few short strings.

    > Andrew, what you write makes sense. I've never really tested it, just
    > read it several places, fx here:
    > http://www.python.org/moin/PythonSpeed/PerformanceTips#stringcat


    This is about making long strings in situations where performance is an
    issue.

    Terry J. Reedy
    Terry Reedy, Apr 11, 2005
    #11
  12. Derek Basch

    Andrew Dalke Guest

    Derek Basch wrote:
    > Interesting stuff Andrew. I do generally avoid string concantination
    > for the reason listed in the Python Performance Tips but your analysis
    > kinda puts that in question.


    Thanks.

    It was interesting for me to. I hadn't looked at the implementation
    for string % before and was rather surprised to find that it
    overallocates 100 bytes to reduce the number of allocs done. It's
    simpler than the implementation I considered.

    Andrew
    Andrew Dalke, Apr 11, 2005
    #12
    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. Gordon Macleod

    Struts iterations

    Gordon Macleod, Jul 21, 2003, in forum: Java
    Replies:
    0
    Views:
    404
    Gordon Macleod
    Jul 21, 2003
  2. Infiniti

    Do something every x iterations

    Infiniti, Jul 7, 2003, in forum: XML
    Replies:
    6
    Views:
    983
    Marrow
    Jul 8, 2003
  3. hilz
    Replies:
    5
    Views:
    532
    Joe Kesselman
    Feb 16, 2006
  4. Derek Basch

    Counting nested loop iterations

    Derek Basch, Mar 16, 2006, in forum: Python
    Replies:
    18
    Views:
    833
    Scott David Daniels
    Mar 17, 2006
  5. edwardfredriks

    counting up instead of counting down

    edwardfredriks, Sep 6, 2005, in forum: Javascript
    Replies:
    6
    Views:
    199
    Dr John Stockton
    Sep 7, 2005
Loading...

Share This Page