Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Python Interview Questions

Reply
Thread Tools

Python Interview Questions

 
 
Chris Angelico
Guest
Posts: n/a
 
      11-19-2012
On Mon, Nov 19, 2012 at 1:09 PM, Roy Smith <(E-Mail Removed)> wrote:
> The theorist understands that a chisel and a screwdriver were intended
> for different purposes, but the pragmatist gets the paint can open.


A good tool can always be used in ways its inventor never intended -
and it will function as its user expects.

$ some_program | egrep --color=always '(ERROR|^)'

will highlight the word ERROR in red anywhere it appears in the
program's output, while maintaining all other lines without color. Not
normal use of grep, to be sure, but quite functional.

A tuple may have been intended to be a record, a struct, whatever, but
it is what it is, and I'll use one any time it's the best tool for the
job. Maybe its immutability is critical; or maybe it's just the most
convenient syntax and all I care about is that it be iterable.

But when I'm explaining grep to someone, I'll describe it as a filter
that keeps only some lines from the original, and when I describe a
tuple, I'll point out that it's immutable and (potentially) hashable.
The obvious first, the unobvious later.

ChrisA
 
Reply With Quote
 
 
 
 
Mark Lawrence
Guest
Posts: n/a
 
      11-19-2012
On 19/11/2012 02:09, Roy Smith wrote:
>
> The theorist understands that a chisel and a screwdriver were intended
> for different purposes, but the pragmatist gets the paint can open.
>


To throw a chiseldriver into the works, IIRC a tuple is way faster to
create but accessing a list is much faster. The obvious snag is that
may have been Python 2.7 whereas 3.3 is completely different. Sorry but
I'm currently wearing my XXXL size Lazy Bone Idle Hat so have no figures
to back my probably incorrect memory up, anyone know anything about this?

--
Cheers.

Mark Lawrence.

 
Reply With Quote
 
 
 
 
Ian Kelly
Guest
Posts: n/a
 
      11-19-2012
On Sun, Nov 18, 2012 at 7:42 PM, Mark Lawrence <(E-Mail Removed)> wrote:
> To throw a chiseldriver into the works, IIRC a tuple is way faster to create
> but accessing a list is much faster. The obvious snag is that may have been
> Python 2.7 whereas 3.3 is completely different. Sorry but I'm currently
> wearing my XXXL size Lazy Bone Idle Hat so have no figures to back my
> probably incorrect memory up, anyone know anything about this?


It's not been my experience with Python 2.7 that list access is faster
than tuple access. Tuples are as fast as or faster than lists, pretty
much universally. They seem to have closed the gap a bit in
Python 3.3, though, as the following timings show. For one-shot
construction, tuples seem to be more efficient for short sequences,
but then lists win for longer sequences, although not by much. Of
course, lists are always going to be much slower if you build them up
with appends and extends.

C:\>python -m timeit -s "x = range(10)" "tuple(x)"
1000000 loops, best of 3: 0.773 usec per loop

C:\>python -m timeit -s "x = range(10)" "list(x)"
1000000 loops, best of 3: 0.879 usec per loop

C:\>python -m timeit -s "x = range(100)" "tuple(x)"
100000 loops, best of 3: 2.88 usec per loop

C:\>python -m timeit -s "x = range(100)" "list(x)"
100000 loops, best of 3: 2.63 usec per loop

C:\>python -m timeit -s "x = range(1000)" "tuple(x)"
10000 loops, best of 3: 37.4 usec per loop

C:\>python -m timeit -s "x = range(1000)" "list(x)"
10000 loops, best of 3: 36.2 usec per loop

C:\>python -m timeit -s "x = range(10000)" "tuple(x)"
1000 loops, best of 3: 418 usec per loop

C:\>python -m timeit -s "x = range(10000)" "list(x)"
1000 loops, best of 3: 410 usec per loop


For iteration, tuples are consistently 7-8% faster.


C:\>python -m timeit -s "x = tuple(range(10))" "for i in x: pass"
1000000 loops, best of 3: 0.467 usec per loop

C:\>python -m timeit -s "x = list(range(10))" "for i in x: pass"
1000000 loops, best of 3: 0.498 usec per loop

C:\>python -m timeit -s "x = tuple(range(100))" "for i in x: pass"
100000 loops, best of 3: 3.31 usec per loop

C:\>python -m timeit -s "x = list(range(100))" "for i in x: pass"
100000 loops, best of 3: 3.56 usec per loop

C:\>python -m timeit -s "x = tuple(range(1000))" "for i in x: pass"
10000 loops, best of 3: 31.6 usec per loop

C:\>python -m timeit -s "x = list(range(1000))" "for i in x: pass"
10000 loops, best of 3: 34.3 usec per loop

C:\>python -m timeit -s "x = tuple(range(10000))" "for i in x: pass"
1000 loops, best of 3: 318 usec per loop

C:\>python -m timeit -s "x = list(range(10000))" "for i in x: pass"
1000 loops, best of 3: 341 usec per loop


For direct item access, tuples seem to be about 2-3% faster.


C:\>python -m timeit -s "import operator as o; x = tuple(range(10)); g
= o.itemgetter(*range(len(x)))" "g(x)"
1000000 loops, best of 3: 0.67 usec per loop

C:\>python -m timeit -s "import operator as o; x = list(range(10)); g
= o.itemgetter(*range(len(x)))" "g(x)"
1000000 loops, best of 3: 0.674 usec per loop

C:\>python -m timeit -s "import operator as o; x = tuple(range(100));
g = o.itemgetter(*range(len(x)))" "g(x)"
100000 loops, best of 3: 4.52 usec per loop

C:\>python -m timeit -s "import operator as o; x = list(range(100)); g
= o.itemgetter(*range(len(x)))" "g(x)"
100000 loops, best of 3: 4.65 usec per loop

C:\>python -m timeit -s "import operator as o; x = tuple(range(1000));
g = o.itemgetter(*range(len(x)))" "g(x)"
10000 loops, best of 3: 43.2 usec per loop

C:\>python -m timeit -s "import operator as o; x = list(range(1000));
g = o.itemgetter(*range(len(x)))" "g(x)"
10000 loops, best of 3: 43.7 usec per loop

C:\>python -m timeit -s "import operator as o; x =
tuple(range(10000)); g = o.itemgetter(*range(len(x)))" "g(x)"
1000 loops, best of 3: 422 usec per loop

C:\>python -m timeit -s "import operator as o; x = list(range(10000));
g = o.itemgetter(*range(len(x)))" "g(x)"
1000 loops, best of 3: 447 usec per loop
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      11-19-2012
On Sun, 18 Nov 2012 21:09:36 -0500, Roy Smith wrote:

> In article <50a97de0$0$29983$c3e8da3$(E-Mail Removed) om>,
> Steven D'Aprano <(E-Mail Removed)> wrote:
>
>
>> > The stack that's returned is a list. It's inherently a list, per the
>> > classic definition:

>>
>> Er, no, it's inherently a blob of multiple text lines.

>
> No, it's a list that looks like (taken from the doc string of the code I
> referenced):
>
> [('/usr/lib/.../base.py', 'get_response'),
> ('/home/songza/.../views.py', 'song_info'),
> ('/home/songza.../api.py', 'get_song'),
> ('/home/songza/.../api.py', 'api')]
>
> [it doesn't really have ...'s in the paths; I just elided some text to
> make it easier to read]


I see. It wasn't clear from your earlier description that the items had
been post-processed from collections of raw log lines to fixed records.
But it doesn't actually change my analysis any. See below.

By the way, based on the sample data you show, your script is possibly
broken. You don't record either the line number that raises, or the
exception raised, so your script doesn't differentiate between different
errors that happen to occur with similar stack traces. (I say "possibly"
broken because I don't know what your requirements are. Maybe your
requirements are sufficiently wide that you don't care that distinct
failures are counted together.)

E.g. these three stack traces will probably generate the same fixed
record, even though the errors are distinct:

#1
Traceback (most recent call last):
File "./spam.py", line 20, in select
selection = func(a, b)
File "./spam.py", line 60, in func
return 1/x
ZeroDivisionError: float division


#2
Traceback (most recent call last):
File "./spam.py", line 20, in select
selection = func(a, b)
File "./spam.py", line 60, in func
return 1/x
TypeError: unsupported operand type(s) for /: 'int' and 'NoneType'


#3
Traceback (most recent call last):
File "./spam.py", line 20, in select
selection = func(a, b)
File "./spam.py", line 55, in func
y = 1/(a + b)
ZeroDivisionError: float division


Maybe that's okay for your application, but it strikes me as odd that you
do distinguish *some* distinct errors in the same function, but not
others.



>> > * It's homogeneous. There's nothing particularly significant about
>> > each entry other than it's the next one in the stack.

>>
>> The complete stack trace is inhomogeneous and immutable. I've already
>> covered immutability above: removing, adding or moving lines will
>> invalidate the stack trace. Inhomogeneity comes from the structure of a
>> stack trace. The mere fact that each line is a string does not mean
>> that any two lines are equivalent. Different lines represent different
>> things.

>
> No. Each entry in the list represents a source file and a function
> name. They're all the same "shape". You could remove one or add
> another one, or shuffle the order, and you would have something which
> was syntactically correct and semantically meaningful (even if it didn't
> represent an actual code path.


If you remove/add/shuffle lines in the stack, you no longer have the same
stack. Take the example you gave before:

stack1 = [('/usr/lib/.../base.py', 'get_response'),
('/home/songza/.../views.py', 'song_info'),
('/home/songza.../api.py', 'get_song'),
('/home/songza/.../api.py', 'api')
]

Here's a different stack trace, representing a different code path, which
as you say is syntactically correct and semantically meaningful:

stack2 = [('/home/songza/.../api.py', 'api'),
('/home/songza.../api.py', 'get_song'),
('/home/songza/.../views.py', 'song_info'),
('/usr/lib/.../base.py', 'get_response')
]

Since they are different stacks, they are treated as different keys:

data = {stack1: 11, stack2: 22}

Do you agree that this is what your application expects? Different stack
traces are different keys, associated with different values.

I claim this only makes sense if you treat the stacks as inherently
immutable. Never mind Python's limitation. Let's pretend we were running
this code under some other language, NeoPython, which allowed mutable
keys.

You claim that stacks are *inherently mutable*. So I should be able to do
this:

stack1.sort() # it's the *same stack*, all I've done is mutate it
print data[stack1]

and expect to see "11" printed. I am looking at the same key, right? So I
certainly don't expect to see the value associated with a completely
different key.

But wait a minute... after sorting, stack1 and stack2 now are equal. I
could just as easily expect to see "22" printed.

I thought we had just agreed that stack1 and stack2 are *different* keys.
Of course they are different. They represent different code paths. But
after sorting stack1, it looks exactly like stack2. It looks like a
different code path. It *lies* -- it no longer represents the code path
that it actually represents, instead it looks like a *different* code
path.

I then generate another stack:

stack3 = [('/home/songza/.../api.py', 'api'),
('/home/songza.../api.py', 'get_song'),
('/home/songza/.../views.py', 'song_info'),
('/usr/lib/.../base.py', 'get_response')
]

should data[stack3] return 11 (it has the same value as stack1) or 22 (it
has the same value as stack2)? Or possibly 33? Or raise KeyError?

Treating stacks in this context as mutable is *incoherent*. It is nice
and convenient to be able to build up a stack trace using a mutable list,
you won't get an argument from me about that, but that can only be
considered a temporary data structure used to build the data structure
you actually care about, which is fixed.

That brings it back to my question: your application is not a counter-
example to my question about using lists as keys, because your data is
not inherently list-like. It is inherently tuple-like, you just build it
using a temporary list. That's perfectly fine, by the way, I do the same
thing.

As you say, the order of the lines in the stack trace is significant. You
cannot expect to mutate the stack and move lines around and treat it as
the same stack. If you move the lines about, it represents a different
stack. That is fundamentally different from the normal use of a list,
where you do expect to be able to move lines about and still have it
count as "the same list".


> I think we're going to have to let this be. You obviously have your
> concept of what a tuple is and what a list is. I disagree.


I think a tuple is an immutable sequence of items, and a list is a
mutable sequence of items.


> I don't
> think either of us is right or wrong, we just have different ways of
> thinking about things.
>
> You come at it from a theoretical point of view.


I certainly do not. My position here is imminently practical. The
alternative, the mutability of keys, is simply incoherent.


> You think of each type
> as an embodiment of certain concepts ("it represents a fixed-length
> heterogenous sequence"). Your thinking is driven by what each type was
> intended to be used for.


Not even close. My thinking is driven by the things each data structure
needs to do. See below.


> I come at it from a practical point of view. To me, each type is a
> collection of methods. I have certain operations I need to perform. I
> pick the type which offers those operations. If the set of operations I
> need to perform (in this case, {append, hash}) don't exist in a single
> type, I'm forced to use both types and convert from one to the other as
> needed.


I don't see that as a problem. Converting from one type to another is
exactly the sort of thing I described in my earlier question.

In your application, you build up a collection of code lines that
represent a stack trace. Here's that example from your own documentation
again:

[('/usr/lib/.../base.py', 'get_response'),
('/home/songza/.../views.py', 'song_info'),
('/home/songza.../api.py', 'get_song'),
('/home/songza/.../api.py', 'api')]

What are the sorts of things I might meaningfully want to do with this
*complete* stack trace?

Add extra lines to it? No. If I needed to add extra lines, it wouldn't be
complete.

Delete lines? Certainly not, that would change the code path it claims to
represent to a code path it doesn't represent.

Sort the list? Reverse it? Heavens no.

If you look at the available list methods, *not one* of the mutating
methods is appropriate to a completed stack trace object. *None* of the
mutator list methods are appropriate once the stack trace object is
complete, and using them would be counter-productive.

If you believe different, then please tell me what mutations your code
actually performs after the stack trace object is completed. In the code
you showed, you throw the list away after turning it into a tuple.

If the object represents a "list of code lines", in the sense of a
mutable Python list rather than a mere sequence, then why don't you use
any list methods on it?

The append method is useful during construction, but that is all. After
the stack is complete, use of any mutator method would be a bug. In other
words, it ought to be immutable, and the use of a list ought to be buried
in the appropriate function as an internal implementation detail. The
public interface ought to be that of an immutable tuple of immutable
strings, because once you have finished building the object, it should
not be possible to mutate it.

This is hardly a theoretical viewpoint. The idea of treating data that
ought not be changed as immutable is borne out of bitter experience of
millions of man-hours tracking down hundreds of thousands of bugs.

(Admittedly not all of those bugs were *my* bugs. I'm talking the
collective experience of programmers over fifty years of coding.)



--
Steven
 
Reply With Quote
 
Terry Reedy
Guest
Posts: n/a
 
      11-19-2012
On 11/19/2012 1:01 AM, Ian Kelly wrote:

> than tuple access. Tuples are as fast as or faster than lists, pretty
> much universally. They seem to have closed the gap a bit in
> Python 3.3, though, as the following timings show. For one-shot
> construction, tuples seem to be more efficient for short sequences,
> but then lists win for longer sequences, although not by much. Of
> course, lists are always going to be much slower if you build them up
> with appends and extends.


Interesting results. But what system (hardware, os). These sorts of
times tend to vary with the system.
>
> C:\>python -m timeit -s "x = range(10)" "tuple(x)"
> 1000000 loops, best of 3: 0.773 usec per loop
>
> C:\>python -m timeit -s "x = range(10)" "list(x)"
> 1000000 loops, best of 3: 0.879 usec per loop
>
> C:\>python -m timeit -s "x = range(100)" "tuple(x)"
> 100000 loops, best of 3: 2.88 usec per loop
>
> C:\>python -m timeit -s "x = range(100)" "list(x)"
> 100000 loops, best of 3: 2.63 usec per loop
>
> C:\>python -m timeit -s "x = range(1000)" "tuple(x)"
> 10000 loops, best of 3: 37.4 usec per loop
>
> C:\>python -m timeit -s "x = range(1000)" "list(x)"
> 10000 loops, best of 3: 36.2 usec per loop
>
> C:\>python -m timeit -s "x = range(10000)" "tuple(x)"
> 1000 loops, best of 3: 418 usec per loop
>
> C:\>python -m timeit -s "x = range(10000)" "list(x)"
> 1000 loops, best of 3: 410 usec per loop
>
>
> For iteration, tuples are consistently 7-8% faster.
>
>
> C:\>python -m timeit -s "x = tuple(range(10))" "for i in x: pass"
> 1000000 loops, best of 3: 0.467 usec per loop
>
> C:\>python -m timeit -s "x = list(range(10))" "for i in x: pass"
> 1000000 loops, best of 3: 0.498 usec per loop
>
> C:\>python -m timeit -s "x = tuple(range(100))" "for i in x: pass"
> 100000 loops, best of 3: 3.31 usec per loop
>
> C:\>python -m timeit -s "x = list(range(100))" "for i in x: pass"
> 100000 loops, best of 3: 3.56 usec per loop
>
> C:\>python -m timeit -s "x = tuple(range(1000))" "for i in x: pass"
> 10000 loops, best of 3: 31.6 usec per loop
>
> C:\>python -m timeit -s "x = list(range(1000))" "for i in x: pass"
> 10000 loops, best of 3: 34.3 usec per loop
>
> C:\>python -m timeit -s "x = tuple(range(10000))" "for i in x: pass"
> 1000 loops, best of 3: 318 usec per loop
>
> C:\>python -m timeit -s "x = list(range(10000))" "for i in x: pass"
> 1000 loops, best of 3: 341 usec per loop
>
>
> For direct item access, tuples seem to be about 2-3% faster.
>
>
> C:\>python -m timeit -s "import operator as o; x = tuple(range(10)); g
> = o.itemgetter(*range(len(x)))" "g(x)"
> 1000000 loops, best of 3: 0.67 usec per loop
>
> C:\>python -m timeit -s "import operator as o; x = list(range(10)); g
> = o.itemgetter(*range(len(x)))" "g(x)"
> 1000000 loops, best of 3: 0.674 usec per loop
>
> C:\>python -m timeit -s "import operator as o; x = tuple(range(100));
> g = o.itemgetter(*range(len(x)))" "g(x)"
> 100000 loops, best of 3: 4.52 usec per loop
>
> C:\>python -m timeit -s "import operator as o; x = list(range(100)); g
> = o.itemgetter(*range(len(x)))" "g(x)"
> 100000 loops, best of 3: 4.65 usec per loop
>
> C:\>python -m timeit -s "import operator as o; x = tuple(range(1000));
> g = o.itemgetter(*range(len(x)))" "g(x)"
> 10000 loops, best of 3: 43.2 usec per loop
>
> C:\>python -m timeit -s "import operator as o; x = list(range(1000));
> g = o.itemgetter(*range(len(x)))" "g(x)"
> 10000 loops, best of 3: 43.7 usec per loop
>
> C:\>python -m timeit -s "import operator as o; x =
> tuple(range(10000)); g = o.itemgetter(*range(len(x)))" "g(x)"
> 1000 loops, best of 3: 422 usec per loop
>
> C:\>python -m timeit -s "import operator as o; x = list(range(10000));
> g = o.itemgetter(*range(len(x)))" "g(x)"
> 1000 loops, best of 3: 447 usec per loop
>



--
Terry Jan Reedy

 
Reply With Quote
 
Roy Smith
Guest
Posts: n/a
 
      11-19-2012
In article <50a9e5cf$0$21863$c3e8da3$(E-Mail Removed) om>,
Steven D'Aprano <(E-Mail Removed)> wrote:

> I see. It wasn't clear from your earlier description that the items had
> been post-processed from collections of raw log lines to fixed records.


Well, I did provide the code that does this.

> But it doesn't actually change my analysis any. See below.
>
> By the way, based on the sample data you show, your script is possibly
> broken. You don't record either the line number that raises, or the
> exception raised, so your script doesn't differentiate between different
> errors that happen to occur with similar stack traces.


You really might want to read the code I provided. Here's the reference
again:

https://bitbucket.org/roysmith/pytho...d/logs/traceba
ck_helper.py

The "header" referred to does indeed contain the exception raised. And
the line numbers are included. Here's a typical output stanza:

2012-11-19T00:00:15+00:00 web5 ˇ˛2012-11-19 00:00:15,831 [2712]:
songza-api IGPhwNU2SJ691cx8 4C0ABFA9-50A974E7-384995 W6D-HSO
173.145.137.54 songza.django.middleware ERROR process_exception() Path =
u'/api/1/station/1459775/next', Exception =
ValueError(u"<SequentialSongPicker: <Station 1459775: u'Old School
105.3'>>: no song ids for mp3",)
/home/songza/env/python/local/lib/python2.7/site-packages/django/core/han
dlers/base.py:111:get_response()
/home/songza/deploy/current/pyza/djapi/decorators.py:11:_wrapped_view_fun
c()
/home/songza/env/python/local/lib/python2.7/site-packages/django/views/de
corators/http.py:45:inner()
/home/songza/deploy/current/pyza/djapi/views.py:1659:station_next()
/home/songza/deploy/current/pyza/models/station.py:660:next_song()
/home/songza/deploy/current/pyza/lib/song_picker.py:327ick()

> I say "possibly" broken because I don't know what your requirements are.


Our requirements are to scan the logs of a production site and filter
down the gobs and gobs of output (we produced 70 GB of log files
yesterday) into something small enough that a human can see what the
most common failures were. The tool I wrote does that.

The rest of this conversation is just silly. It's turning into getting
hit on the head lessons.
 
Reply With Quote
 
Roy Smith
Guest
Posts: n/a
 
      11-19-2012
OK, I've just read back over the whole thread. I'm really struggling to
understand what point you're trying to make. I started out by saying:

> Use a list when you need an ordered collection which is mutable (i.e.
> can be altered after being created). Use a tuple when you need an
> immutable list (such as for a dictionary key).


To which you obviously objected. So now you write:

> I think a tuple is an immutable sequence of items, and a list is a
> mutable sequence of items.


So how is that different from what I said? Is this whole argument
boiling down to your use of "immutable sequence" vs. my use of
"immutable list"?
 
Reply With Quote
 
Ian Kelly
Guest
Posts: n/a
 
      11-19-2012
On Mon, Nov 19, 2012 at 7:30 AM, Roy Smith <(E-Mail Removed)> wrote:
> In article <50a9e5cf$0$21863$c3e8da3$(E-Mail Removed) om>,
> Steven D'Aprano <(E-Mail Removed)> wrote:
>>
>> By the way, based on the sample data you show, your script is possibly
>> broken. You don't record either the line number that raises, or the
>> exception raised, so your script doesn't differentiate between different
>> errors that happen to occur with similar stack traces.

>
> You really might want to read the code I provided. Here's the reference
> again:
>
> https://bitbucket.org/roysmith/pytho...d/logs/traceba
> ck_helper.py
>
> The "header" referred to does indeed contain the exception raised. And
> the line numbers are included. Here's a typical output stanza:


Yes, but the dict is still keyed on the traceback alone, and only the
first header for a particular traceback is stored. If two different
exceptions occur at the same line of code and sharing the same
traceback, the second exception would be counted as a second
occurrence of the first, effectively squashing any reporting of the
second exception.
 
Reply With Quote
 
Terry Reedy
Guest
Posts: n/a
 
      11-19-2012
On 11/19/2012 9:30 AM, Roy Smith wrote:

> Our requirements are to scan the logs of a production site and filter
> down the gobs and gobs of output (we produced 70 GB of log files
> yesterday) into something small enough that a human can see what the
> most common failures were. The tool I wrote does that.
>
> The rest of this conversation is just silly. It's turning into getting
> hit on the head lessons.


I agree. In early Python, tuples were more different from lists than
they are today. They did not have any (public) methods. Today, they have
..index and .count methods, which make little sense from the 'tuple is a
record' viewpoint. The addition of those methods redefined tuples as
read-only (and therefore hashable) sequences.

From the collections.abc doc
'''
Sequence | Sized, Iterable, Container |
__getitem__ __contains__, __iter__, __reversed__, index, and count
....
class collections.abc.Sequence
class collections.abc.MutableSequence
ABCs for read-only and mutable sequences.
'''
>>> from collections.abc import Sequence
>>> issubclass(tuple, Sequence)

True

--
Terry Jan Reedy

 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      11-19-2012
On Mon, 19 Nov 2012 09:30:54 -0500, Roy Smith wrote:

> In article <50a9e5cf$0$21863$c3e8da3$(E-Mail Removed) om>,
> Steven D'Aprano <(E-Mail Removed)> wrote:
>
>> I see. It wasn't clear from your earlier description that the items had
>> been post-processed from collections of raw log lines to fixed records.

>
> Well, I did provide the code that does this.


You did? When? [goes back and looks]

Oh, so you did. Oops.

By the way, your news client seems to be mangling long URLs, by splitting
them when they exceed the maximum line length. I didn't follow the link
you gave because it was mangled, and then forgot it even existed. Sorry
about that.


[...]
> You really might want to read the code I provided. Here's the reference
> again:
>
> https://bitbucket.org/roysmith/pytho...18d175ed/logs/

traceba
> ck_helper.py


And mangled again


> The "header" referred to does indeed contain the exception raised. And
> the line numbers are included. Here's a typical output stanza:

[snip]

Ian Kelly has picked up on what I'm trying to say. You might collect the
traceback in the "header", but it doesn't get used in the key, and each
time you find a repeated stack trace, you toss away whatever header you
just saw and keep the header you saw the first time.

[quote]
header, stack = traceback_helper.extract_stack(lines)
signature = tuple(stack)
if signature in crashes:
count, header = crashes[signature]
crashes[signature] = (count + 1, header)
else:
crashes[signature] = (1, header)
[end quote]


In general, it is an unsafe assumption that the actual exception raised
will be the same just because the stack trace is the same. So as I said,
if you have two *distinct* failures occurring in the same function (not
even necessarily on the same line), your code appears to treat them as
the same error. That seems odd to me, but if you have a good reason for
doing it that way, so be it.



--
Steven
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Please come and add questions to C++ interview questions onListenVoice Vijay C++ 2 05-07-2010 03:02 PM
Re: Anyone read "Python Interview Questions: Python CertificationReview"? Steve Holden Python 0 03-04-2009 02:44 PM
Re: Anyone read "Python Interview Questions: Python CertificationReview"? Tim Chase Python 0 03-04-2009 01:45 PM
ASP Interview Questions ASP Interview Questions reema ASP General 0 08-26-2008 11:57 AM
.NET Interview Question, C#, ASP.NET Interview Questions dotnetuncle Javascript 0 10-30-2007 03:08 PM



Advertisments