default value for list access?

B

Bo Peng

Dear list,

My program needs to do calculation based on a giving data structure
(like a sparse matrix) with lots of missing values (invalid
indices/keys of lists/dictionaries).

The programing is difficult in that I have to use a try...except block
for every item access. I have written a function

def getItem(item, idx, default):
try:
return item[idx]
except:
return default

Then I will have to write a[1]['a'][4] as

getItem( getItem( getItem(a,1,{}), 'a', []), 4, 0)

Is there any way to automatically return 0 when any exception is raised
for such data acceses? (automatic wrapping a[...] as
try:
a[...]
except:
0
)

Many thanks in advance.

Bo
 
B

Bo Peng

To clearify the problem:

The data is the count of something, for example a[90]=10. a may be a
dictionary if the range is huge and a list when the range is reasonably
small. In the dictionary case, I can use a.setdefault(80, 0) if key 80
does not exist. In the list case, I have to check the length of list
before I access it (or use exception).

This becomes troublesome when I need to do the following a lot.

b = a[80][1] + a[80][2] + a[80][3]

If I use the getItem function in my previous email, it will look like

b = getItem(getItem(a, 80, []), 1, 0) + getItem(getItem(a, 80, []),
2, 0) + getItem(getItem(a, 80, []), 3, 0)

What would be the best solution to handle this? Something like

b = df( a[80][1], 0) + df( a[80][2], 0) + df( a[80][3], 0)

would be reasonable but df can not be easily defined since the exception
will be raised before function df is called. Something like

b = df( a, [80, 1], 0) + df( a, [80,2], 0) + df( a, [80, 3], 0)

would work if df is defined as

def df(a, idx, default):
try:
for i in range(0, idx):
a = a[ idx ]
return a
except:
return 0

but I am afraid that a for loop would bring serious performance problem.

Thanks.

Bo
 
R

Ruslan Spivak

Ð’ Ð’Ñк, 27/02/2005 в 14:03 -0600, Bo Peng пишет:
To clearify the problem:

The data is the count of something, for example a[90]=10. a may be a
dictionary if the range is huge and a list when the range is reasonably
small. In the dictionary case, I can use a.setdefault(80, 0) if key 80
does not exist. In the list case, I have to check the length of list
before I access it (or use exception).

This becomes troublesome when I need to do the following a lot.

b = a[80][1] + a[80][2] + a[80][3]

If I use the getItem function in my previous email, it will look like

b = getItem(getItem(a, 80, []), 1, 0) + getItem(getItem(a, 80, []),
2, 0) + getItem(getItem(a, 80, []), 3, 0)

What would be the best solution to handle this? Something like

b = df( a[80][1], 0) + df( a[80][2], 0) + df( a[80][3], 0)

would be reasonable but df can not be easily defined since the exception
will be raised before function df is called. Something like

b = df( a, [80, 1], 0) + df( a, [80,2], 0) + df( a, [80, 3], 0)

would work if df is defined as

def df(a, idx, default):
try:
for i in range(0, idx):
a = a[ idx ]
return a
except:
return 0

but I am afraid that a for loop would bring serious performance problem.

Thanks.

Bo


I'm not sure if that's suitable for you, but you could define your own
subclasses for 'dict' and 'list' and specify your specific behaviour you
would like.

For dict something like this:

class MyDict(dict):
def __getitem__(self, key):
try:
return super(MyDict, self).__getitem__(key)
except:
return 0

a = MyDcit()

Ruslan
 
P

Peter Hansen

Bo said:
The data is the count of something, for example a[90]=10. a may be a
dictionary if the range is huge and a list when the range is reasonably
small. In the dictionary case, I can use a.setdefault(80, 0) if key 80
does not exist. In the list case, I have to check the length of list
before I access it (or use exception).

This becomes troublesome when I need to do the following a lot.

b = a[80][1] + a[80][2] + a[80][3]

If I use the getItem function in my previous email, it will look like

b = getItem(getItem(a, 80, []), 1, 0) + getItem(getItem(a, 80, []), 2,
0) + getItem(getItem(a, 80, []), 3, 0)

What would be the best solution to handle this?

Sounds to me like the best solution is to simplify the implementation
and dispense with the list alternative. Why use a list if a dictionary
is suitable? Don't say performance: that's premature optimization.
Dictionaries already have what you need, apparently, with setdefault(),
so just use them and keep the code simple.

....
but I am afraid that a for loop would bring serious performance problem.

More premature optimization? The first rule of programming should be
to make it work. Then consider making it faster, but only if it is
really unacceptably slow. (Some would say to make it work, then make
it "right", then make it fast. In this case, "right" doesn't mean
"correct" (that's the first step), it means making it clean and simple.
Doing it this way makes sense only if you have a really good test
suite developed along with the code, ala test-driven development.
Lacking that, you should focus on "right" and working together,
which in this case suggests leaving out the complicated list option.)

-Peter
 
B

Bo Peng

Sounds to me like the best solution is to simplify the implementation
and dispense with the list alternative. Why use a list if a dictionary
is suitable? Don't say performance: that's premature optimization.
Dictionaries already have what you need, apparently, with setdefault(),
so just use them and keep the code simple.

You are right that if I use all dictionaries, I can use
a.setdefault(4,{}).setdefault(2,0)
to access a[4][2]. Not too bad compared to the getItem function.

However, this is an scientific application. Data are stored internally
in C format and exposed to Python as python array (arraymodule). I guess
the best way is to modify the arraymodule interface and stop it from
raising an exception when index is out of range. (similar to Ruslan's
solution). But this means too much trouble for now.

I will use the df(a, idx, default) method and see if its performance is
acceptable.

Thanks.
Bo
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top