Comparison problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Chris

    #1

    Comparison problem

    Hi,

    I'm new to python, and I'm trying to write a small python script for a
    webpage. The script opens up a file called inventory, reads the
    contents, and checks the contents against the data from the form in my
    webpage. Now I have to do some slicing to get the name of the form
    elements (in this case, checkboxes), to resemble the values in the
    inventory file. Here's my python part:

    #!/usr/local/bin/python
    import cgi
    import types
    from Cookie import *
    form=cgi.FieldS torage()
    user_answer=[]
    error='false'
    item=''
    qty=''
    def main():
    print"Content-type: text/html\n"
    i=open("invento ry","r")
    keys=form.keys( )
    for key in keys:
    field=form[key]
    if type(field)==ty pes.InstanceTyp e:
    item=field.valu e
    if item[0:1]=="-":
    item=item[ :-7]
    item=item[1:]
    infile=open("in ventory","r")
    while infile:
    dummy=infile.re adline()
    if dummy=='':break
    print item
    print ", "+dummy
    if (dummy == item): <This comparison isn't working>
    print"Found it"
    else:
    print"Didn\'t Find it"
    print "<br>"
    infile.close()
    else:
    #print" Quantity: "
    #print item
    print"<br>"
    #print field.value
    else:
    print"BAD"
    main()

    Let me know if more information is needed. Any assistance will be
    greatly appreciated.

  • Tom Anderson

    #2
    Re: Comparison problem

    Chris, as well as addressing what i think is causing your problem, i'm
    going to point out some bits of your code that i think could be polished a
    little. It's intended in a spirit of constructive criticism, so i hope you
    don't mind!

    On Sat, 26 Nov 2005, Chris wrote:
    [color=blue]
    > if item[0:1]=="-":[/color]

    item[0:1] seems a rather baroque way of writing item[0]! I'd actually
    suggest writing this line like this:

    if item.startswith ("-:):

    As i feel it's more readable.
    [color=blue]
    > item=item[ :-7]
    > item=item[1:][/color]

    You could just write:

    item = item[1:7]

    For those two lines.
    [color=blue]
    > infile=open("in ventory","r")[/color]

    The "r" isn't necessary - reading is the default mode for files. You could
    argue that this documents your intentions towards the file, i suppose, but
    the traditional python idiom would leave it out.
    [color=blue]
    > while infile:
    > dummy=infile.re adline()[/color]

    The pythonic idiom for this is:

    for dummy in infile:

    Although i'd strongly suggest you change 'dummy' to a more descriptive
    variable name; i use 'line' myself.

    Now, this is also the line that i think is at the root of your trouble:
    readline returns lines with the line-terminator ('\n' or whatever it is on
    your system) still on them. That gets you into trouble later - see below.

    When i'm iterating over lines in a file, the first thing i do with the
    line is chomp off any trailing newline; the line after the for loop is
    typically:

    line = line.rstrip("\n ")
    [color=blue]
    > if dummy=='':break[/color]

    You don't by any chance mean 'continue' here, do you?
    [color=blue]
    > print item
    > print ", "+dummy
    > if (dummy == item): <This comparison isn't working>[/color]

    This is where it all falls down - i suspect that what's happening here is
    that dummy has a trailing newline, and item doesn't, so although they look
    very similar, they're not the same string, so the comparison comes out
    false. Try throwing in that rstrip at the head of the loop and see if it
    fixes it.

    HTH.

    tom

    --
    Gotta treat 'em mean to make 'em scream.

    Comment

    • Peter Hansen

      #3
      Re: Comparison problem

      Tom Anderson wrote:[color=blue]
      > On Sat, 26 Nov 2005, Chris wrote:
      >[color=green]
      >> if item[0:1]=="-":[/color]
      >
      > item[0:1] seems a rather baroque way of writing item[0]! I'd actually
      > suggest writing this line like this:[/color]

      Actually, it's not so much baroque as it is safe... item[0] will fail if
      the string is empty, while item[0:1] will return '' in that case.

      Of course, as you point out, .startswith() is the better approach anyway.

      -Peter

      Comment

      • Tom Anderson

        #4
        Re: Comparison problem

        On Sat, 26 Nov 2005, Peter Hansen wrote:
        [color=blue]
        > Tom Anderson wrote:[color=green]
        >> On Sat, 26 Nov 2005, Chris wrote:
        >>[color=darkred]
        >>> if item[0:1]=="-":[/color]
        >>
        >> item[0:1] seems a rather baroque way of writing item[0]! I'd actually
        >> suggest writing this line like this:[/color]
        >
        > Actually, it's not so much baroque as it is safe... item[0] will fail if
        > the string is empty, while item[0:1] will return '' in that case.[/color]

        Ah i didn't realise that. Whether that's safe rather depends on what the
        subsequent code does with an empty string - an empty string might be some
        sort of error (in this particular case, it would mean that the loop test
        had gone wrong, since bool("") == False), and the slicing behaviour would
        constitute silent passing of an error.

        But, more importantly, egad! What's the thinking behind having slicing
        behave like that? Anyone got any ideas? What's the use case, as seems to
        be the fashionable way of putting it these days? :)

        tom

        --
        This should be on ox.boring, shouldn't it?

        Comment

        • Peter Hansen

          #5
          Re: Comparison problem

          Tom Anderson wrote:[color=blue]
          > On Sat, 26 Nov 2005, Peter Hansen wrote:[color=green]
          >>Tom Anderson wrote:[color=darkred]
          >>>On Sat, 26 Nov 2005, Chris wrote:
          >>>> if item[0:1]=="-":
          >>>
          >>>item[0:1] seems a rather baroque way of writing item[0]! I'd actually
          >>>suggest writing this line like this:[/color]
          >>
          >>Actually, it's not so much baroque as it is safe... item[0] will fail if
          >>the string is empty, while item[0:1] will return '' in that case.[/color]
          >
          > Ah i didn't realise that. Whether that's safe rather depends on what the
          > subsequent code does with an empty string -[/color]

          I meant "safe" as in "doesn't throw an exception", as item[0] will when
          passed an empty string... sometimes you don't want code to throw an
          exception, and you don't want to have to do a separate test for certain
          conditions that might do so. This technique is one example.
          [color=blue]
          > an empty string might be some
          > sort of error (in this particular case, it would mean that the loop test
          > had gone wrong, since bool("") == False), and the slicing behaviour would
          > constitute silent passing of an error.
          >
          > But, more importantly, egad! What's the thinking behind having slicing
          > behave like that? Anyone got any ideas? What's the use case, as seems to
          > be the fashionable way of putting it these days? :)[/color]

          Well, since slicing is (I believe, and speaking only roughly) supposed
          to return a sequence of the same type as that on which it's operating,
          what would be the alternative? Unless you allow slicing to return None,
          or raise an exception in certain cases, return a null sequence of the
          appropriate type seems to be perfectly logical behaviour when the
          requested slice doesn't exist in the input.

          But I'm not sure this is from a specific use case so much as a side
          effect of other more desirable behaviours of slicing. Asking for this
          to behave differently without analyzing the impact it has on slicing in
          general is likely to overlook something crucial...

          -Peter

          Comment

          • Alex Martelli

            #6
            Re: Comparison problem

            Tom Anderson <twic@urchin.ea rth.li> wrote:
            ...[color=blue]
            > But, more importantly, egad! What's the thinking behind having slicing
            > behave like that? Anyone got any ideas? What's the use case, as seems to
            > be the fashionable way of putting it these days? :)[/color]

            Slicing has always been "soft" (it's OK to specify slice indices beyond
            the boundaries) while indexing has always been "hard" (specifying an
            index beyond the boundaries raises an exception). It does allow simpler
            and more concise expression of conditions on slices, without requiring
            you to guard the test on the slice with another test on the sequence's
            length. For example, to say "those sublists of lists-of-lists bigL that
            don't end in [...1,2,3]" you can code

            [L for L in bigL if L[-3:] != [1,2,3]]

            instead of

            [L for L in bigL if len(L) < 3 or L[-3:] != [1,2,3]]

            Introducing the endswith and startswith string methods lowered the
            usefulness of soft slicing for such tests on strings (since it
            subtracted some specific use cases), but not all sequences have such
            specialized methods, and not all use cases of soft slicing are tests.
            E.g., "remove the last character of s (if any)" can be compactly
            expressed with "s=s[:-1]" rather than "s=s and s[:-1]" or more expansive
            testing. No big deal, but then again I don't recall any situation in
            which getting an exception from slicing (as opposed to indexing) would
            have helped me catch a bug faster.


            Alex

            Comment

            • Fredrik Lundh

              #7
              Re: Comparison problem

              Peter Hansen wrote:
              [color=blue]
              > Actually, it's not so much baroque as it is safe... item[0] will fail if
              > the string is empty, while item[0:1] will return '' in that case.
              >
              > Of course, as you point out, .startswith() is the better approach anyway.[/color]

              $ timeit -s "s = 'abc'" "s[:1] == 'a'"
              1000000 loops, best of 3: 0.852 usec per loop

              $ timeit -s "s = 'abc'; w ='a'" "s[:len(w)] == w"
              1000000 loops, best of 3: 1.27 usec per loop

              $ timeit -s "s = 'abc'; c=s.startswith" "c('a')"
              1000000 loops, best of 3: 1.75 usec per loop

              $ timeit -s "s = 'abc'" "s.startswith(' a')"
              100000 loops, best of 3: 2.28 usec per loop

              </F>



              Comment

              • bonono@gmail.com

                #8
                Re: Comparison problem

                I think no matter what language you programs it, it is hard to
                understand. Can you break it up into sub-problems first ? Like first
                parsing the inventory file into a python dict, then also the fields
                from web to another dict ?

                Chris wrote:[color=blue]
                > Hi,
                >
                > I'm new to python, and I'm trying to write a small python script for a
                > webpage. The script opens up a file called inventory, reads the
                > contents, and checks the contents against the data from the form in my
                > webpage. Now I have to do some slicing to get the name of the form
                > elements (in this case, checkboxes), to resemble the values in the
                > inventory file. Here's my python part:
                >
                > #!/usr/local/bin/python
                > import cgi
                > import types
                > from Cookie import *
                > form=cgi.FieldS torage()
                > user_answer=[]
                > error='false'
                > item=''
                > qty=''
                > def main():
                > print"Content-type: text/html\n"
                > i=open("invento ry","r")
                > keys=form.keys( )
                > for key in keys:
                > field=form[key]
                > if type(field)==ty pes.InstanceTyp e:
                > item=field.valu e
                > if item[0:1]=="-":
                > item=item[ :-7]
                > item=item[1:]
                > infile=open("in ventory","r")
                > while infile:
                > dummy=infile.re adline()
                > if dummy=='':break
                > print item
                > print ", "+dummy
                > if (dummy == item): <This comparison isn't working>
                > print"Found it"
                > else:
                > print"Didn\'t Find it"
                > print "<br>"
                > infile.close()
                > else:
                > #print" Quantity: "
                > #print item
                > print"<br>"
                > #print field.value
                > else:
                > print"BAD"
                > main()
                >
                > Let me know if more information is needed. Any assistance will be
                > greatly appreciated.[/color]

                Comment

                • Peter Hansen

                  #9
                  Re: Comparison problem

                  Fredrik Lundh wrote:[color=blue]
                  > Peter Hansen wrote:[color=green]
                  >>Actually, it's not so much baroque as it is safe... item[0] will fail if
                  >>the string is empty, while item[0:1] will return '' in that case.
                  >>
                  >>Of course, as you point out, .startswith() is the better approach anyway.[/color]
                  >
                  > $ timeit -s "s = 'abc'" "s[:1] == 'a'"
                  > 1000000 loops, best of 3: 0.852 usec per loop
                  >
                  > $ timeit -s "s = 'abc'; w ='a'" "s[:len(w)] == w"
                  > 1000000 loops, best of 3: 1.27 usec per loop
                  >
                  > $ timeit -s "s = 'abc'; c=s.startswith" "c('a')"
                  > 1000000 loops, best of 3: 1.75 usec per loop
                  >
                  > $ timeit -s "s = 'abc'" "s.startswith(' a')"
                  > 100000 loops, best of 3: 2.28 usec per loop[/color]

                  "Unless you have a need to optimize, in which case use timeit to find
                  which approach works better. If speed is not your primary concern, then
                  ..startswith() is probably the better approach since it is more readable
                  to most people."

                  Thanks for the help with expanding on my original statement /F. ;-)

                  -Peter

                  Comment

                  • Tim Henderson

                    #10
                    Re: Comparison problem

                    of course the more correct way is most likely the use of short circuit
                    evaluation. so somthing along lines of

                    if (len(item) > 0) and (item[0] == '-'): pass

                    would probably be the correct approach.

                    Comment

                    • Tim Henderson

                      #11
                      Re: Comparison problem

                      peter

                      would not the more correct way to do this be short circuit
                      evaluation. somthing along lines of

                      if (len(item) > 0) and (item[0] == '-'): pass

                      seems to be the more correct approach. rather than relying on slicing
                      to return an empty string. For instance suppose you wanted to test to
                      see if than spot contained an empty string. If you used the slice
                      meathod you would be in a pickle. However in this particular case it
                      seems to be clear that the use of .startswith() is the single best
                      approach.

                      Comment

                      • Peter Hansen

                        #12
                        Re: Comparison problem

                        Tim Henderson wrote:[color=blue]
                        > peter[/color]

                        (Thanks for clarifying to whom you were responding... I saw the other
                        post but wouldn't have responded since it didn't seem to be in response
                        to one of mine. :-) )
                        [color=blue]
                        > would not the more correct way to do this be short circuit
                        > evaluation. somthing along lines of
                        >
                        > if (len(item) > 0) and (item[0] == '-'): pass[/color]

                        This is "correct" only in a narrow sense. I wouldn't call it "correct
                        Python" if I saw it in code around here. Most likely (since this always
                        depends on context), I would replace it with this:

                        if item and item[0] == '-':
                        pass

                        I think it's probably unlikely that the first test would be needed only
                        on that one line, so it's even more likely that "if item" test would be
                        done first, by itself, and then other tests on item[0] would be done.

                        If this was code that needed high performance (i.e. had been detected
                        with proper profiling as a serious bottleneck) then the slicing approach
                        would be better (as Fredrik demonstrated).

                        Hmm... just realized we're going way off track, since we actually have
                        the original code here and don't need to comment on hypotheticals.

                        It appears to me that the original input is being treated as some sort
                        of fixed-length record, with certain characters and text in predefined
                        positions, specified by index number. With that in mind, I'd actually
                        say the original code is just fine with "if item[0:1] == '-'" and given
                        the context it is pretty readable (ignoring the awful formatting with no
                        whitespace around operators) and "correct". Using ".startswit h()" might
                        have been equally appropriate, but without knowing more detail of the
                        input data I couldn't say.

                        -Peter

                        Comment

                        Working...