Re: Confused compare function :)

Discussion in 'Python' started by Bruno Dupuis, Dec 6, 2012.

  1. Bruno Dupuis

    Bruno Dupuis Guest

    On Wed, Dec 05, 2012 at 11:50:49PM +0100, Anatoli Hristov wrote:
    > I'm confused again with a compare update function. The problem is that
    > my function does not work at all and I don't get it where it comes
    > from.
    >
    > in my DB I have total of 754 products. when I run the function is says:
    > Total updated: 754
    > Total not found with in the distributor: 747
    > I just don't get it, can you find my mistake ?
    >
    > Thanks in advance
    >
    > def Change_price():
    > total = 0
    > tnf = 0
    > for row in DB: # DB is mySQL DB, logically I get out 1 SKU and I
    > compare it with next loop
    > isku = row["sku"]
    > isku = isku.lower()
    > iprice = row["price"]
    > iprice = int(iprice)
    > found = 0
    > try:
    > for x in PRICELIST:# here is my next loop in a CSV file
    > which is allready in a list PRICELIST
    > try:
    > dprice = x[6]
    > dprice = dprice.replace(",",".") # As in the
    > PRICELIST the prices are with commas I replace the comma as python
    > request it
    > dprice = float(dprice)
    > newprice = round(dprice)*1.10
    > dsku = x[4]
    > dsku = dsku.lower()
    > stock = int(x[7])
    > if isku == dsku and newprice < int(iprice):# If
    > found the coresponded SKU and the price is higher than the one in the
    > CSV I update the price
    > print dsku, x[6], dprice, newprice
    > Update_SQL(newprice, isku)# goes to the SQL Update
    > print isku, newprice
    > if isku == dsku:# Just a check to see if it works
    > print "Found %s" %dsku
    > found = 1
    > else:
    > found = 0
    > except IndexError:
    > pass
    > except ValueError:
    > pass
    > except TypeError:
    > pass
    > except IndexError:
    > pass
    > if found == 1:
    > print "%s This is match" % isku
    > if found == 0:
    > print "%s Not found" % isku
    > tnf = tnf +1
    > total = total +1
    > print "Total updated: %s" % total
    > print"Total not found with in the distributor: %s" % tnf


    I tried, I swear I did try, I didn't understand the whole algorithm of the
    function. However, in a first sight, I find it way to deeply nested.
    def ... for ... try ... for ... if ... if. Can't you split it in several
    function, or in methods of a callable class? Somtimes it's finally much
    more clear and the errors become obvious. Another advice: never ever

    except XXXError:
    pass

    at least log, or count, or warn, or anything, but don't pass. I bet your
    missing products have disapeared into those black holes.

    mmmh, now, i see that you set found to 1 only if newprice <int(iprice)...
    new_price is a float (newprice = round(dprice)*1.10) that you compare with
    an int? is that correct? seems strangee to me.

    --
    Bruno Dupuis
     
    Bruno Dupuis, Dec 6, 2012
    #1
    1. Advertising

  2. On Thu, 06 Dec 2012 01:19:58 +0100, Bruno Dupuis wrote:

    > I tried, I swear I did try, I didn't understand the whole algorithm of
    > the function. However, in a first sight, I find it way to deeply nested.


    Yes!

    But basically, the code seems to run a pair of nested for-loops:

    for SKU in database:
    for SKU in csv file:
    if the two SKUs match:
    compare their prices and update the database



    > def ... for ... try ... for ... if ... if.


    You missed a second try.

    > Can't you split it in several
    > function, or in methods of a callable class? Somtimes it's finally much
    > more clear and the errors become obvious. Another advice: never ever
    >
    > except XXXError:
    > pass
    >
    > at least log, or count, or warn, or anything, but don't pass. I bet your
    > missing products have disapeared into those black holes.


    I think that "never" is too strong, but otherwise I agree with you.


    > mmmh, now, i see that you set found to 1 only if newprice
    > <int(iprice)... new_price is a float (newprice = round(dprice)*1.10)
    > that you compare with an int? is that correct? seems strangee to me.



    There's nothing wrong with comparing floats to ints.

    However, possibly iprice is not intended to be an int. The code is rather
    confused and the names are at best obscure and at worst actively
    misleading. I assumed that prices must be ints, (iprice means "integer
    price"?) but that might not be the case, since later on another price is
    multiplied by 1.10.

    Also I wonder if the code is meant to calculate the new price:

    newprice = round(dprice)*1.10 # dprice is the price in the CSV file!

    or perhaps it is meant to be:

    newprice = int(round(dprice*1.10))


    That seems likely.


    --
    Steven
     
    Steven D'Aprano, Dec 6, 2012
    #2
    1. Advertising

  3. Bruno Dupuis

    Rotwang Guest

    On 06/12/2012 00:19, Bruno Dupuis wrote:
    > [...]
    >
    > Another advice: never ever
    >
    > except XXXError:
    > pass
    >
    > at least log, or count, or warn, or anything, but don't pass.


    Really? I've used that kind of thing several times in my code. For
    example, there's a point where I have a list of strings and I want to
    create a list of those ints that are represented in string form in my
    list, so I do this:

    listofints = []
    for k in listofstrings:
    try:
    listofints.append(int(k))
    except ValueError:
    pass

    Another example: I have a dialog box with an entry field where the user
    can specify a colour by entering a string, and a preview box showing the
    colour. I want the preview to automatically update when the user has
    finished entering a valid colour string, so whenever the entry field is
    modified I call this:

    def preview(*args):
    try:
    previewbox.config(bg = str(entryfield.get()))
    except tk.TclError:
    pass

    Is there a problem with either of the above? If so, what should I do
    instead?


    --
    I have made a thing that superficially resembles music:

    http://soundcloud.com/eroneity/we-berated-our-own-crapiness
     
    Rotwang, Dec 6, 2012
    #3
  4. On Thu, 06 Dec 2012 03:22:53 +0000, Rotwang wrote:

    > On 06/12/2012 00:19, Bruno Dupuis wrote:
    >> [...]
    >>
    >> Another advice: never ever
    >>
    >> except XXXError:
    >> pass
    >>
    >> at least log, or count, or warn, or anything, but don't pass.

    >
    > Really? I've used that kind of thing several times in my code. For
    > example, there's a point where I have a list of strings and I want to
    > create a list of those ints that are represented in string form in my
    > list, so I do this:
    >
    > listofints = []
    > for k in listofstrings:
    > try:
    > listofints.append(int(k))
    > except ValueError:
    > pass
    >
    > Another example: I have a dialog box with an entry field where the user
    > can specify a colour by entering a string, and a preview box showing the
    > colour. I want the preview to automatically update when the user has
    > finished entering a valid colour string, so whenever the entry field is
    > modified I call this:
    >
    > def preview(*args):
    > try:
    > previewbox.config(bg = str(entryfield.get()))
    > except tk.TclError:
    > pass
    >
    > Is there a problem with either of the above? If so, what should I do
    > instead?


    They're fine.

    Never, ever say that people should never, ever do something.


    *cough*


    --
    Steven
     
    Steven D'Aprano, Dec 6, 2012
    #4
  5. Bruno Dupuis

    Bruno Dupuis Guest

    On Thu, Dec 06, 2012 at 04:32:34AM +0000, Steven D'Aprano wrote:
    > On Thu, 06 Dec 2012 03:22:53 +0000, Rotwang wrote:
    >
    > > On 06/12/2012 00:19, Bruno Dupuis wrote:
    > >> [...]
    > >>
    > >> Another advice: never ever
    > >>
    > >> except XXXError:
    > >> pass
    > >>
    > >> at least log, or count, or warn, or anything, but don't pass.

    > >
    > > Really? I've used that kind of thing several times in my code. For
    > > example, there's a point where I have a list of strings and I want to
    > > create a list of those ints that are represented in string form in my
    > > list, so I do this:
    > >
    > > listofints = []
    > > for k in listofstrings:
    > > try:
    > > listofints.append(int(k))
    > > except ValueError:
    > > pass
    > >
    > > Another example: I have a dialog box with an entry field where the user
    > > can specify a colour by entering a string, and a preview box showing the
    > > colour. I want the preview to automatically update when the user has
    > > finished entering a valid colour string, so whenever the entry field is
    > > modified I call this:
    > >
    > > def preview(*args):
    > > try:
    > > previewbox.config(bg = str(entryfield.get()))
    > > except tk.TclError:
    > > pass
    > >
    > > Is there a problem with either of the above? If so, what should I do
    > > instead?

    >
    > They're fine.
    >
    > Never, ever say that people should never, ever do something.
    >
    >
    > *cough*
    >


    Well, dependening on the context (who provides listofstrings?) I would
    log or count errors on the first one... or not.

    On the second one, I would split the expression, because (not sure of
    that point, i didn't import tk for years) previewbox.config and
    entryfield.get may raise a tk.TclError for different reasons.

    The point is Exceptions are made for error handling, not for normal
    workflow. I hate when i read that for example:

    try:
    do_stuff(mydict[k])
    except KeyError:
    pass

    (loads of them in many libraries and frameworks)
    instead of:

    if k in mydict:
    do_stuff(mydict[k])

    Note that the performances are better with the latter.

    There are some exceptions to this, though, like StopIteration

    For me, it's a rule of thumb, except: pass is possible in situations
    where I control every input data, and I deeply, exactly know all code
    interractions. If figuring all this out is longer (it's almost always
    the case) than typing:

    log.warning('oops:\n %s' % traceback.format_exc())

    I log.

    It depends also on the context, I'd be more 'permissive' a short
    script than into a large program, framework, or lib, for the
    very reason it's easy to know all code interactions.

    In my coder life, i spent more time debugging silently swallowed exceptions
    than logging abnormal behaviours.

    --
    Bruno Dupuis
     
    Bruno Dupuis, Dec 6, 2012
    #5
  6. On Thu, Dec 6, 2012 at 7:49 PM, Bruno Dupuis
    <> wrote:
    >
    > The point is Exceptions are made for error handling, not for normal
    > workflow. I hate when i read that for example:
    >
    > try:
    > do_stuff(mydict[k])
    > except KeyError:
    > pass
    >
    > (loads of them in many libraries and frameworks)
    > instead of:
    >
    > if k in mydict:
    > do_stuff(mydict[k])
    >
    > Note that the performances are better with the latter.
    >


    This is the age-old question of EAFP vs LBYL.

    The check-first "Look Before You Leap" option has a small chance of
    race condition. If something changes between the 'if' and the usage,
    maybe from another thread or maybe a signal handler or perhaps some
    object's __del__ method gets called or who knows what, you'll have a
    problem.

    Python's usual philosophy is that it's Easier to Ask Forgiveness than
    Permission. Just do it, and jump out if you can't. This technique
    plays *very* nicely with generic handlers. For instance, at work I
    wrote an HTTP daemon that's supposed to receive XML-encoded POST data
    with a particular structure. The handler function (called once for
    every HTTP request) looks something like this, in Pythonesque
    pseudocode:

    def handler(req):
    try:
    msg = parse_xml(req.body) # returns a dict of dicts/lists/strings
    stuff = msg["soapenv:Envelope"]["soapenv:Body"]["GetItemTransactionsResponse"]
    sig = stuff["Item"]["ApplicationData"]
    if sig.does.not.match(): return "Bad request"
    sscanf(sig,"FOO %d %d %d",account,table,row)
    accountdata[account][table][row] = 1
    return "Done and successful."
    except:
    log_error_to_stderr()
    return "Done."

    I don't particularly care _what_ the error is. Most of the time, I
    won't even bother to look at the log file (it's run via an Upstart
    job, and stderr is redirected to a file), but if I'm having problems,
    I can go check. Generally, exceptions thrown by that code are the
    result of malformed info packets; since it's basic HTTP, it's easy for
    anyone to send a request in, and I don't care to see those errors
    logged. In fact, the logging to stderr can even get commented out in
    production, and used only when there's actually a problem being
    diagnosed.

    To try to handle all possible errors in that code by LBLY, I would
    need to pepper the code with conditions and an appropriate 'return'
    statement (and, though the pseudo-code has the function returning a
    string, the actual code involves an explicit "send this response"
    call). Plus, I'd need to predict every possible failure. With EAFP,
    all I need is one simple "catch" handler for the whole block of code,
    and I can easily eyeball just a few function exit points to see that
    an appropriate HTTP response will always be sent.

    Each has its place.

    ChrisA
     
    Chris Angelico, Dec 6, 2012
    #6
  7. On Thu, 06 Dec 2012 09:49:26 +0100, Bruno Dupuis wrote:

    > The point is Exceptions are made for error handling, not for normal
    > workflow.


    That's certainly not the case in Python. Using exceptions for flow
    control is a standard part of the language.

    IndexError and StopIteration are used to detect the end of lists or
    iterators in for loops.

    GeneratorExit is used to request that generators exit.

    SysExit is used to exit the interpreter.


    There is nothing wrong with using exceptions for flow control in
    moderation.


    > I hate when i read that for example:
    >
    > try:
    > do_stuff(mydict[k])
    > except KeyError:
    > pass
    >
    > (loads of them in many libraries and frameworks) instead of:
    >
    > if k in mydict:
    > do_stuff(mydict[k])
    >
    > Note that the performances are better with the latter.


    Not so. Which one is faster will depend on how often you expect to fail.
    If the keys are nearly always present, then:

    try:
    do_stuff(mydict[k])
    except KeyError:
    pass

    will be faster. Setting up a try block is very fast, about as fast as
    "pass", and faster than "if k in mydict".

    But if the key is often missing, then catching the exception will be
    slow, and the "if k in mydict" version may be faster. It depends on how
    often the key is missing.


    [...]
    > It depends also on the context, I'd be more 'permissive' a short script
    > than into a large program, framework, or lib, for the very reason it's
    > easy to know all code interactions.
    >
    > In my coder life, i spent more time debugging silently swallowed
    > exceptions than logging abnormal behaviours.



    That's fine. I agree with you about not silently swallowing errors. Where
    I disagree is that you said "never ever", which is an exaggeration.
    Remember that exceptions are not always errors.

    Problem: take a list of strings, and add up the ones which are integers,
    ignoring everything else.

    Solution:

    total = 0
    for s in list_of_strings:
    try:
    total += int(s)
    except ValueError:
    pass # Not a number, ignore it.


    Why would you want to log that? It's not an error, it is working as
    designed. I hate software that logs every little thing that happens, so
    that you cannot tell what's important and what isn't.



    --
    Steven
     
    Steven D'Aprano, Dec 6, 2012
    #7
  8. Bruno Dupuis

    peter Guest

    On 12/06/2012 08:47 AM, Steven D'Aprano wrote:
    > On Thu, 06 Dec 2012 09:49:26 +0100, Bruno Dupuis wrote:
    >
    >> The point is Exceptions are made for error handling, not for normal
    >> workflow.

    > That's certainly not the case in Python. Using exceptions for flow
    > control is a standard part of the language.
    >
    > IndexError and StopIteration are used to detect the end of lists or
    > iterators in for loops.
    >
    > GeneratorExit is used to request that generators exit.
    >
    > SysExit is used to exit the interpreter.
    >
    >
    > There is nothing wrong with using exceptions for flow control in
    > moderation.
    >
    >
    >> I hate when i read that for example:
    >>
    >> try:
    >> do_stuff(mydict[k])
    >> except KeyError:
    >> pass
    >>
    >> (loads of them in many libraries and frameworks) instead of:
    >>
    >> if k in mydict:
    >> do_stuff(mydict[k])
    >>
    >> Note that the performances are better with the latter.

    > Not so. Which one is faster will depend on how often you expect to fail.
    > If the keys are nearly always present, then:
    >
    > try:
    > do_stuff(mydict[k])
    > except KeyError:
    > pass
    >
    > will be faster. Setting up a try block is very fast, about as fast as
    > "pass", and faster than "if k in mydict".
    >
    > But if the key is often missing, then catching the exception will be
    > slow, and the "if k in mydict" version may be faster. It depends on how
    > often the key is missing.
    >
    >
    > [...]
    >> It depends also on the context, I'd be more 'permissive' a short script
    >> than into a large program, framework, or lib, for the very reason it's
    >> easy to know all code interactions.
    >>
    >> In my coder life, i spent more time debugging silently swallowed
    >> exceptions than logging abnormal behaviours.

    >
    > That's fine. I agree with you about not silently swallowing errors. Where
    > I disagree is that you said "never ever", which is an exaggeration.
    > Remember that exceptions are not always errors.
    >
    > Problem: take a list of strings, and add up the ones which are integers,
    > ignoring everything else.
    >
    > Solution:
    >
    > total = 0
    > for s in list_of_strings:
    > try:
    > total += int(s)
    > except ValueError:
    > pass # Not a number, ignore it.
    >
    >
    > Why would you want to log that? It's not an error, it is working as
    > designed. I hate software that logs every little thing that happens, so
    > that you cannot tell what's important and what isn't.
    >
    >
    >

    Is perfectly right to use try catch for a flow control.
    Just think in something more complex like this.

    try:
    self._conn = MySQLdb.connect(host=host,
    user=user,
    passwd=passwd,
    db=db)
    except:
    logging.info("Error de conexion con la base de datos")
    inform(subject = 'Db down on app %s' % app, body=sbody)

    Or maybe something like this.

    try:
    cursor.execute(sqli, data)
    self._conn.commit()
    except:
    try:
    self._conn.rollback()
    cursor.execute(sqli, data)
    self._conn.commit()
    except Exception, e:
    pass
    # print e
    # logging.info('ERROR en la insercion %s' % e)

    This is pretty dumb, but is a valid example, on what you can do with try
    catch
     
    peter, Dec 6, 2012
    #8
  9. On Thu, Dec 6, 2012 at 10:47 PM, Steven D'Aprano
    <> wrote:
    > Not so. Which one is faster will depend on how often you expect to fail.
    > If the keys are nearly always present, then:
    >
    > try:
    > do_stuff(mydict[k])
    > except KeyError:
    > pass
    >
    > will be faster. Setting up a try block is very fast, about as fast as
    > "pass", and faster than "if k in mydict".
    >
    > But if the key is often missing, then catching the exception will be
    > slow, and the "if k in mydict" version may be faster. It depends on how
    > often the key is missing.
    >


    Setting up the try/except is a constant time cost, while the
    duplicated search for k inside the dictionary might depend on various
    other factors. In the specific case of a Python dictionary, the
    membership check is fairly cheap (assuming you're not the subject of a
    hash collision attack - Py3.3 makes that a safe assumption), but if
    you were about to execute a program and wanted to first find out if it
    existed, that extra check could be ridiculously expensive, eg if the
    path takes you on a network drive - or, worse, on multiple network
    drives, which I have had occasion to do!

    ChrisA
     
    Chris Angelico, Dec 6, 2012
    #9
  10. Bruno Dupuis

    Hans Mulder Guest

    On 6/12/12 12:55:16, peter wrote:
    > Is perfectly right to use try catch for a flow control.
    > Just think in something more complex like this.
    >
    > try:
    > self._conn = MySQLdb.connect(host=host,
    > user=user,
    > passwd=passwd,
    > db=db)
    > except:
    > logging.info("Error de conexion con la base de datos")
    > inform(subject = 'Db down on app %s' % app, body=sbody)


    This is an example of the sort of incorrect code you
    should try to avoid. An improved version is:

    self._conn = MySQLdb.connect(host=host,
    user=user,
    passwd=passwd,
    db=db)

    By not catching the exception, you're allowing the
    Python interpreter to report what the problem was,
    for example "Keyboard interrupt" or "Access denied".

    By report "DB down" when there is no reason to assume
    that that is the problem, you're confusing the user.

    > Or maybe something like this.
    >
    > try:
    > cursor.execute(sqli, data)
    > self._conn.commit()
    > except:
    > try:
    > self._conn.rollback()
    > cursor.execute(sqli, data)
    > self._conn.commit()
    > except Exception, e:
    > pass
    > # print e
    > # logging.info('ERROR en la insercion %s' % e)


    This is another example of what not to do. Even the
    commented-out print statement loses information, viz.
    the traceback.

    If you leave out the try/except, then more accurate
    information will be printed, and a programmer who needs
    to fix the problem, can run the code under the debugger
    and it will automatically stop at the point where the
    uncaught exception is raised. That's much easier than
    having to set breakpoints at all the "except Exception:"
    clauses in a typical chunk of hard-to-maintain code.

    Context managers were invented to make it easier to do
    this sort of thing correctly. For example:

    with sqlite3.connect(dbpath) as connection:
    connection.cursor().execute(sqli, data)

    If the flow reaches the end of the "with" command,
    the connection object will self.commit() automatically.
    If an exception is raised, the connection object will
    self.rollback() automatically. No try/except required.

    This is shorter, and much easier to get right.

    > This is pretty dumb, but is a valid example, on what you can
    > do with try catch


    It is an unfortunate fact of life that you can write code
    that is hard to maintain. The fact that you *can* do this,
    does not mean that you should.


    Hope this helps,

    -- HansM
     
    Hans Mulder, Dec 6, 2012
    #10
  11. Am 06.12.2012 09:49 schrieb Bruno Dupuis:

    > The point is Exceptions are made for error handling, not for normal
    > workflow. I hate when i read that for example:
    >
    > try:
    > do_stuff(mydict[k])
    > except KeyError:
    > pass


    I as well, but for other reasons (see below). But basically this is EAFP.


    > (loads of them in many libraries and frameworks)
    > instead of:
    >
    > if k in mydict:
    > do_stuff(mydict[k])


    This is LBYL, C-style, not Pythonic.

    I would do

    try:
    value = mydict[k]
    except KeyError:
    pass
    else:
    do_stuff(k)

    Why? Because do_stuff() might raise a KeyError, which should not go
    undetected.


    Thomas
     
    Thomas Rachel, Dec 6, 2012
    #11
  12. On Fri, Dec 7, 2012 at 12:32 AM, Hans Mulder <> wrote:
    > On 6/12/12 12:55:16, peter wrote:
    >> Is perfectly right to use try catch for a flow control.
    >> Just think in something more complex like this.
    >>
    >> try:
    >> self._conn = MySQLdb.connect(host=host,
    >> user=user,
    >> passwd=passwd,
    >> db=db)
    >> except:
    >> logging.info("Error de conexion con la base de datos")
    >> inform(subject = 'Db down on app %s' % app, body=sbody)

    >
    > This is an example of the sort of incorrect code you
    > should try to avoid. An improved version is:
    >
    > self._conn = MySQLdb.connect(host=host,
    > user=user,
    > passwd=passwd,
    > db=db)
    >
    > By not catching the exception, you're allowing the
    > Python interpreter to report what the problem was,
    > for example "Keyboard interrupt" or "Access denied".
    >
    > By report "DB down" when there is no reason to assume
    > that that is the problem, you're confusing the user.


    The problem with the original example is that it has a bare except,
    which will catch too much. Call it an oversimplified example, perhaps
    :) By not catching the exception, you doom your entire script to
    abort. What Steven called felicide is catching exceptions *and
    immediately exiting*, which offers little benefit over just letting
    the exception propagate up.

    >> Or maybe something like this.
    >>
    >> try:
    >> cursor.execute(sqli, data)
    >> self._conn.commit()
    >> except:
    >> try:
    >> self._conn.rollback()
    >> cursor.execute(sqli, data)
    >> self._conn.commit()
    >> except Exception, e:
    >> pass
    >> # print e
    >> # logging.info('ERROR en la insercion %s' % e)

    >
    > This is another example of what not to do. Even the
    > commented-out print statement loses information, viz.
    > the traceback.
    >
    > If you leave out the try/except, then more accurate
    > information will be printed, and a programmer who needs
    > to fix the problem, can run the code under the debugger
    > and it will automatically stop at the point where the
    > uncaught exception is raised. That's much easier than
    > having to set breakpoints at all the "except Exception:"
    > clauses in a typical chunk of hard-to-maintain code.


    Again, oversimplified example. If this were real code, I'd criticize
    the bare except (and the "except Exception", which has the same
    problem).

    > Context managers were invented to make it easier to do
    > this sort of thing correctly. For example:
    >
    > with sqlite3.connect(dbpath) as connection:
    > connection.cursor().execute(sqli, data)
    >
    > If the flow reaches the end of the "with" command,
    > the connection object will self.commit() automatically.
    > If an exception is raised, the connection object will
    > self.rollback() automatically. No try/except required.
    >
    > This is shorter, and much easier to get right.


    But it does something completely different. The original code's logic
    is: Try the query, then commit. If that fails, roll back and have
    another shot at it. This is dangerous if there could have been other
    statements in the transaction (they won't be retried), but otherwise,
    it's a reasonable way of dealing with serialization failures. It has
    its risks, of course, but it's not meant to be a demo of database
    code, it's a demo of try/except.

    >> This is pretty dumb, but is a valid example, on what you can
    >> do with try catch

    >
    > It is an unfortunate fact of life that you can write code
    > that is hard to maintain. The fact that you *can* do this,
    > does not mean that you should.


    Agreed. However, the mere presence of try/except does not make code
    unmaintainable, nor is it a strong indication that the code already
    was.

    ChrisA
     
    Chris Angelico, Dec 6, 2012
    #12
  13. Bruno Dupuis

    Neil Cerutti Guest

    On 2012-12-06, Steven D'Aprano
    <> wrote:
    > total = 0
    > for s in list_of_strings:
    > try:
    > total += int(s)
    > except ValueError:
    > pass # Not a number, ignore it.


    If it's internal data, perhaps. Of course, that would mean I had
    the option of *not* creating that stupid list_of_strings.

    --
    Neil Cerutti
     
    Neil Cerutti, Dec 6, 2012
    #13
  14. On Fri, Dec 7, 2012 at 12:33 AM, Thomas Rachel
    <>
    wrote:
    > Am 06.12.2012 09:49 schrieb Bruno Dupuis:
    >
    >> The point is Exceptions are made for error handling, not for normal
    >> workflow. I hate when i read that for example:
    >>
    >> try:
    >> do_stuff(mydict[k])
    >> except KeyError:
    >> pass

    >
    > I would do
    >
    > try:
    > value = mydict[k]
    > except KeyError:
    > pass
    > else:
    > do_stuff(k)
    >
    > Why? Because do_stuff() might raise a KeyError, which should not go
    > undetected.


    (Assuming first off that you meant "do_stuff(value)", not
    "do_stuff(k)", in that last line)

    That has quite different functionality, though. The original wouldn't
    have called do_stuff at all if k is not in dict, behaviour which is
    matched by both his EAFP and his LBLY. But your version, in the event
    of a KeyError, will call do_stuff with the previous value of value, or
    raise NameError if there is no such previous value. I don't think
    that's intentional.

    The only way around it that I can see is an extra condition or jump -
    something like:

    def call_if_present(mydict,k,do_stuff):
    """Equivalent to
    do_stuff(mydict[k])
    if the key is present; otherwise, does not call do_stuff, and
    returns None."""
    try:
    value = mydict[k]
    except KeyError:
    return
    return do_stuff(value)

    It'll propagate any other exceptions from the subscripting (eg
    TypeError if you give it a list instead of a dict), and any exceptions
    from do_stuff itself. But it's getting a bit unwieldy.

    ChrisA
     
    Chris Angelico, Dec 6, 2012
    #14
  15. Bruno Dupuis

    Hans Mulder Guest

    On 6/12/12 14:58:01, Chris Angelico wrote:
    > On Fri, Dec 7, 2012 at 12:33 AM, Thomas Rachel
    > <>
    > wrote:
    >> > Am 06.12.2012 09:49 schrieb Bruno Dupuis:
    >> >
    >>> >> The point is Exceptions are made for error handling, not for normal
    >>> >> workflow. I hate when i read that for example:
    >>> >>
    >>> >> try:
    >>> >> do_stuff(mydict[k])
    >>> >> except KeyError:
    >>> >> pass
    >> >
    >> > I would do
    >> >
    >> > try:
    >> > value = mydict[k]
    >> > except KeyError:
    >> > pass
    >> > else:
    >> > do_stuff(k)
    >> >
    >> > Why? Because do_stuff() might raise a KeyError, which should not go
    >> > undetected.


    > (Assuming first off that you meant "do_stuff(value)", not
    > "do_stuff(k)", in that last line)


    > That has quite different functionality, though. The original wouldn't
    > have called do_stuff at all if k is not in dict, behaviour which is
    > matched by both his EAFP and his LBLY. But your version, in the event
    > of a KeyError, will call do_stuff with the previous value of value, or
    > raise NameError if there is no such previous value. I don't think
    > that's intentional.


    Errhm, no. Look again. The do_stuff(value) call is in the "else:"
    clause, so it will only be done of there was no Exception of any
    kind, and in that case the assignment to value must have succeeded.

    -- HansM
     
    Hans Mulder, Dec 6, 2012
    #15
  16. Guys I'm still confusing my script is working better, but not enough.
    I did a logfile to see which products are not found anymore in the CSV
    and I found some that are present but python says they are not ??

    Here is the product in the CSV:
    MONIIE2407HDS-B1;MON;II;E2407HDS-B1;E2407HDS-B1;IIYAMA LCD 24" Wide
    1920x1080TN Speakers 2ms Black DVI HDMI;133;20;RECTD0.41;0,41;;;;;;;;;

    Here is what python reports:
    e2208hds-b2, 721 not found
    e2273hds-b1, 722 not found
    e2274hds-b2, 723 not found
    e2407hds-b1, 724 not found

    And here is my final code: ( I hope it look better now :) )

    def Change_price(): # Changes the price in the DB if the price in the
    CSV is changed
    TotalUpdated = 0 # Counter for total updated
    TotalSKUFound = 0 # Total SKU from the DB coresponds to the one in the CSV
    TotalSKUinDB = 0 # Total SKU in the DB
    for row in PRODUCTSDB:
    TotalSKUinDB +=1
    db_sku = row["sku"].lower()
    db_price = float(row["price"])
    found = False
    try:
    for x in pricelist:
    try:
    csv_price = x[6]
    csv_price = csv_price.replace(",",".")
    csv_price = float(csv_price)
    csv_new_price = csv_price*1.10
    csv_sku = x[4].lower()
    csv_stock = int(x[7]) # I used this as normally I
    used stock in the condition
    match = re.search(db_sku, csv_sku)
    if len(db_sku) != 0 and match:
    TotalSKUFound +=1
    if csv_new_price < db_price and csv_stock > 0:
    print db_sku, csv_price, db_price, csv_new_price
    Update_SQL(csv_new_price, db_sku)
    TotalUpdated += 1
    found = True

    except IndexError: # I have a lot of index error in
    the CSV (empty fields) and the loop gives "index error" I don't care
    about them
    pass
    except ValueError:
    pass
    except TypeError:
    pass
    except IndexError:
    pass
    if not found: WriteLog(db_sku, db_sku,)
    TotalNotFound = TotalSKUinDB - TotalSKUFound
    print "Total SKU in the DB %s" % TotalSKUinDB
    print "Total SKU coresponds to the DB and CSV %s" % TotalSKUFound
    print "Total updated: %s" % TotalUpdated
    print"Total not found with in the distributor: %s" % TotalNotFound
     
    Anatoli Hristov, Dec 6, 2012
    #16
  17. On Fri, Dec 7, 2012 at 1:21 AM, Hans Mulder <> wrote:
    > Errhm, no. Look again. The do_stuff(value) call is in the "else:"
    > clause, so it will only be done of there was no Exception of any
    > kind, and in that case the assignment to value must have succeeded.


    DOH! My bad. Sorry! I somehow didn't see your else, *and* didn't think
    of that clause when doing up my "fixed" version. Yep, else is
    precisely what this calls for, and (assuming the change I mentioned)
    your code does indeed match the original.

    ChrisA
     
    Chris Angelico, Dec 6, 2012
    #17
  18. Bruno Dupuis

    Dave Angel Guest

    On 12/06/2012 08:58 AM, Chris Angelico wrote:
    > On Fri, Dec 7, 2012 at 12:33 AM, Thomas Rachel
    > <>
    > wrote:
    >> Am 06.12.2012 09:49 schrieb Bruno Dupuis:
    >>
    >>> The point is Exceptions are made for error handling, not for normal
    >>> workflow. I hate when i read that for example:
    >>>
    >>> try:
    >>> do_stuff(mydict[k])
    >>> except KeyError:
    >>> pass

    >> I would do
    >>
    >> try:
    >> value = mydict[k]
    >> except KeyError:
    >> pass
    >> else:
    >> do_stuff(k)
    >>
    >> Why? Because do_stuff() might raise a KeyError, which should not go
    >> undetected.

    > (Assuming first off that you meant "do_stuff(value)", not
    > "do_stuff(k)", in that last line)
    >
    > That has quite different functionality, though. The original wouldn't
    > have called do_stuff at all if k is not in dict, behaviour which is
    > matched by both his EAFP and his LBLY. But your version, in the event
    > of a KeyError, will call do_stuff with the previous value of value, or
    > raise NameError if there is no such previous value.


    Nope. The else clause will only execute if no exception occurs in the
    value= line.

    > I don't think
    > that's intentional.
    >
    > The only way around it that I can see is an extra condition or jump -
    > something like:
    >
    > def call_if_present(mydict,k,do_stuff):
    > """Equivalent to
    > do_stuff(mydict[k])
    > if the key is present; otherwise, does not call do_stuff, and
    > returns None."""
    > try:
    > value = mydict[k]
    > except KeyError:
    > return
    > return do_stuff(value)
    >
    > It'll propagate any other exceptions from the subscripting (eg
    > TypeError if you give it a list instead of a dict), and any exceptions
    > from do_stuff itself. But it's getting a bit unwieldy.
    >
    > ChrisA



    --

    DaveA
     
    Dave Angel, Dec 6, 2012
    #18
  19. Bruno Dupuis

    peter Guest

    On 12/06/2012 10:58 AM, Chris Angelico wrote:
    > On Fri, Dec 7, 2012 at 12:33 AM, Thomas Rachel
    > <>
    > wrote:
    >> Am 06.12.2012 09:49 schrieb Bruno Dupuis:
    >>
    >>> The point is Exceptions are made for error handling, not for normal
    >>> workflow. I hate when i read that for example:
    >>>
    >>> try:
    >>> do_stuff(mydict[k])
    >>> except KeyError:
    >>> pass

    >> I would do
    >>
    >> try:
    >> value = mydict[k]
    >> except KeyError:
    >> pass
    >> else:
    >> do_stuff(k)
    >>
    >> Why? Because do_stuff() might raise a KeyError, which should not go
    >> undetected.

    > (Assuming first off that you meant "do_stuff(value)", not
    > "do_stuff(k)", in that last line)
    >
    > That has quite different functionality, though. The original wouldn't
    > have called do_stuff at all if k is not in dict, behaviour which is
    > matched by both his EAFP and his LBLY. But your version, in the event
    > of a KeyError, will call do_stuff with the previous value of value, or
    > raise NameError if there is no such previous value. I don't think
    > that's intentional.
    >
    > The only way around it that I can see is an extra condition or jump -
    > something like:
    >
    > def call_if_present(mydict,k,do_stuff):
    > """Equivalent to
    > do_stuff(mydict[k])
    > if the key is present; otherwise, does not call do_stuff, and
    > returns None."""
    > try:
    > value = mydict[k]
    > except KeyError:
    > return
    > return do_stuff(value)
    >
    > It'll propagate any other exceptions from the subscripting (eg
    > TypeError if you give it a list instead of a dict), and any exceptions
    > from do_stuff itself. But it's getting a bit unwieldy.
    >
    > ChrisA

    Ok, is seems like my example code, don't like :). Is ok, it was a poor
    example.
    This a more complex example that create a python daemons process.
    In these case you see the help of try catch. To watch an Operating
    system problem (80% of the cases), when the fork is created. Or you can
    initialize a logging (in the catch statement)
    and watch the log file with tail -f.


    import sys, os
    def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
    # Perform first fork.
    try:
    pid = os.fork( )
    if pid > 0:
    sys.exit(0) # Exit first parent.
    except OSError, e:
    sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno,
    e.strerror))
    sys.exit(1)
    # Decouple from parent environment.
    os.chdir("/")
    os.umask(0)
    os.setsid( )
    # Perform second fork.
    try:
    pid = os.fork( )
    if pid > 0:
    sys.exit(0) # Exit second parent.
    except OSError, e:
    sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno,
    e.strerror))
    sys.exit(1)
    # The process is now daemonized, redirect standard file descriptors.
    for f in sys.stdout, sys.stderr: f.flush( )
    si = file(stdin, 'r')
    so = file(stdout, 'a+')
    se = file(stderr, 'a+', 0)
    os.dup2(si.fileno( ), sys.stdin.fileno( ))
    os.dup2(so.fileno( ), sys.stdout.fileno( ))
    os.dup2(se.fileno( ), sys.stderr.fileno( ))

    Or imagine that you are manage master-slave's connections (for examples
    to an ldap databse - or a monitor system tools), you can use try catch.
    If all the server's are down, maybe you want to be inform about it, you
    can put a function to send a email to your account

    In simple works try: catch is 'GOOD'.

    ipserver = {"192.168.1.13": ["monitoreo", 22],
    "192.168.1.18": ["usuarios-dns", 22, 53, 139, 389, 445,
    631, 3306, 4900, 8765],
    "192.168.1.72": ["sistemas-ldap", 22, 80, 139, 389, 445,
    631, 3306, 4900, 8765],
    "192.168.1.74": ["terminales", 22,139, 445, 389, 4900],
    "192.168.1.80": ["backup", 22, 139, 445],
    "192.168.1.1": ["router", 21, 22, 25, 80, 110, 143, 465, 3128],
    "192.168.1.90": ["router", 5900]
    }

    def portstatus(self, **kwargs):
    ports = kwargs.get("ports")
    server = kwargs.get("server")
    if len(ports) > 0:
    logging.info("chequeando puertos %s" % server)
    for a in ports:
    try:
    sock = socket()
    sock.connect((server,a))
    sock.close
    except:
    logging.info("informando errores en puerto %s" % a)
    today = str(datetime.today())
    subprocess.Popen("for a in $(seq 1 15); do beep;
    done", shell=True)
    self.sendreport(ip=server, server=server,
    cuerpo="El puerto %s esta caido en %s - %s" % (a, server, today),
    asunto="El puerto %s esta caido en %s - %s" % (a, server, today))
    else:
    logging.info("no hay puertos que chequear")
     
    peter, Dec 6, 2012
    #19
  20. On Thu, Dec 6, 2012 at 3:22 PM, Anatoli Hristov <> wrote:
    > Guys I'm still confusing my script is working better, but not enough.
    > I did a logfile to see which products are not found anymore in the CSV
    > and I found some that are present but python says they are not ??
    >
    > Here is the product in the CSV:
    > MONIIE2407HDS-B1;MON;II;E2407HDS-B1;E2407HDS-B1;IIYAMA LCD 24" Wide
    > 1920x1080TN Speakers 2ms Black DVI HDMI;133;20;RECTD0.41;0,41;;;;;;;;;
    >
    > Here is what python reports:
    > e2208hds-b2, 721 not found
    > e2273hds-b1, 722 not found
    > e2274hds-b2, 723 not found
    > e2407hds-b1, 724 not found
    >
    > And here is my final code: ( I hope it look better now :) )
    >
    > def Change_price(): # Changes the price in the DB if the price in the
    > CSV is changed
    > TotalUpdated = 0 # Counter for total updated
    > TotalSKUFound = 0 # Total SKU from the DB coresponds to the one in the CSV
    > TotalSKUinDB = 0 # Total SKU in the DB
    > for row in PRODUCTSDB:
    > TotalSKUinDB +=1
    > db_sku = row["sku"].lower()
    > db_price = float(row["price"])
    > found = False
    > try:
    > for x in pricelist:
    > try:
    > csv_price = x[6]
    > csv_price = csv_price.replace(",",".")
    > csv_price = float(csv_price)
    > csv_new_price = csv_price*1.10
    > csv_sku = x[4].lower()
    > csv_stock = int(x[7]) # I used this as normally I
    > used stock in the condition
    > match = re.search(db_sku, csv_sku)
    > if len(db_sku) != 0 and match:
    > TotalSKUFound +=1
    > if csv_new_price < db_price and csv_stock > 0:
    > print db_sku, csv_price, db_price, csv_new_price
    > Update_SQL(csv_new_price, db_sku)
    > TotalUpdated += 1
    > found = True
    >
    > except IndexError: # I have a lot of index error in
    > the CSV (empty fields) and the loop gives "index error" I don't care
    > about them
    > pass
    > except ValueError:
    > pass
    > except TypeError:
    > pass
    > except IndexError:
    > pass
    > if not found: WriteLog(db_sku, db_sku,)
    > TotalNotFound = TotalSKUinDB - TotalSKUFound
    > print "Total SKU in the DB %s" % TotalSKUinDB
    > print "Total SKU coresponds to the DB and CSV %s" % TotalSKUFound
    > print "Total updated: %s" % TotalUpdated
    > print"Total not found with in the distributor: %s" % TotalNotFound


    No one have an idea ?

    Thanks
     
    Anatoli Hristov, Dec 6, 2012
    #20
    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. Sullivan WxPyQtKinter
    Replies:
    5
    Views:
    447
    Rene Pijlman
    Mar 7, 2006
  2. Xiaoshen Li

    confused with function declarations

    Xiaoshen Li, Dec 21, 2005, in forum: C Programming
    Replies:
    10
    Views:
    541
    Flash Gordon
    Dec 22, 2005
  3. Lee Fleming
    Replies:
    49
    Views:
    825
    Steve Holden
    Aug 14, 2007
  4. xkenneth
    Replies:
    7
    Views:
    451
  5. Anatoli Hristov

    Confused compare function :)

    Anatoli Hristov, Dec 5, 2012, in forum: Python
    Replies:
    2
    Views:
    199
    Anatoli Hristov
    Dec 6, 2012
Loading...

Share This Page