Re: Is there a short-circuiting dictionary "get" method?

2005-03-11 Thread Duncan Booth
Bengt Richter wrote:

> then there's always
> 
>if 'x' in d: value = d['x']
>else: value = bsf()
> 
> or
> 
>try: value = d['x']
>except KeyError: value = bsf()
> 

Its worth remembering that the first of those two suggestions is also 
faster than using get, so you aren't losing on speed if you write the code 
out in full: choose whichever seems clearest and uses the least contorted 
code.

(The second is the fastest of all if the value is found, but a lot slower 
if the exception gets thrown.)

C:\Python24\Lib>timeit.py -s "d={}" -s "for k in range(1000): d['x%s'%k]=k" 
"value = d.get('x45', 'notfound')"
100 loops, best of 3: 0.427 usec per loop

C:\Python24\Lib>timeit.py -s "d={}" -s "for k in range(1000): d['x%s'%k]=k" 
"value = d.get('z45', 'notfound')"
100 loops, best of 3: 0.389 usec per loop

C:\Python24\Lib>timeit.py -s "d={}" -s "for k in range(1000): d['x%s'%k]=k" 
"if 'x45' in d: value=d['x45']" "else: value='notfound'"
100 loops, best of 3: 0.259 usec per loop

C:\Python24\Lib>timeit.py -s "d={}" -s "for k in range(1000): d['x%s'%k]=k" 
"if 'z45' in d: value=d['z45']" "else: value='notfound'"
100 loops, best of 3: 0.131 usec per loop

C:\Python24\Lib>timeit.py -s "d={}" -s "for k in range(1000): d['x%s'%k]=k" 
"try: value=d['x45']" "except: value='notfound'"
100 loops, best of 3: 0.158 usec per loop

C:\Python24\Lib>timeit.py -s "d={}" -s "for k in range(1000): d['x%s'%k]=k" 
"try: value=d['z45']" "except: value='notfound'"
10 loops, best of 3: 2.71 usec per loop
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-11 Thread Bengt Richter
On Fri, 11 Mar 2005 04:12:19 -0500, Steve Holden <[EMAIL PROTECTED]> wrote:

>Terry Reedy wrote:
>> "Skip Montanaro" <[EMAIL PROTECTED]> wrote in message 
>> news:[EMAIL PROTECTED]
>> 
>>>   value = d.get('x') or bsf()
>>>
>>>Of course, this bsf() will get called if d['x'] evaluates to false, not 
>>>just
>>>None,
>> 
>> 
>> value = (d.get('x') is not None) or bsf() #??
>> 
>Unfortunately this will set value to True for all non-None values of 
>d['x']. Suppose d['x'] == 3:
>
>  >>> 3 is not None
>True
>  >>>
>
maybe (untested)
   value = ('x' in d and [d['x']] or [bsf()])[0]

then there's always

   if 'x' in d: value = d['x']
   else: value = bsf()

or

   try: value = d['x']
   except KeyError: value = bsf()


Regards,
Bengt Richter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-11 Thread Steve Holden
Terry Reedy wrote:
"Skip Montanaro" <[EMAIL PROTECTED]> wrote in message 
news:[EMAIL PROTECTED]

  value = d.get('x') or bsf()
Of course, this bsf() will get called if d['x'] evaluates to false, not 
just
None,

value = (d.get('x') is not None) or bsf() #??
Unfortunately this will set value to True for all non-None values of 
d['x']. Suppose d['x'] == 3:

 >>> 3 is not None
True
 >>>
regards
 Steve
--
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-10 Thread Terry Reedy

"Skip Montanaro" <[EMAIL PROTECTED]> wrote in message 
news:[EMAIL PROTECTED]
>value = d.get('x') or bsf()
>
> Of course, this bsf() will get called if d['x'] evaluates to false, not 
> just
> None,

value = (d.get('x') is not None) or bsf() #??

tjr



-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-10 Thread Skip Montanaro

Dave> In this snippet:
Dave> d = {'x': 1}
Dave> value = d.get('x', bigscaryfunction())

Dave> the bigscaryfunction is always called, even though 'x' is a valid
Dave> key. 

I sometimes use

value = d.get('x') or bsf()

Of course, this bsf() will get called if d['x'] evaluates to false, not just
None, so it won't work in all situations.  It may help often enough to be
useful though.

Skip
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Jeff Epler
untested

def my_getter(m, i, f):
try:
return m[i]
except (KeyError, IndexError):
return f()

my_getter(d, 'x', bigscaryfunction)
my_getter(d, 'y', lambda: scaryinlineexpresion)


pgp04VRKFqQL1.pgp
Description: PGP signature
-- 
http://mail.python.org/mailman/listinfo/python-list

Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Michael Spencer
Dave Opstad wrote:
In this snippet:
d = {'x': 1}
value = d.get('x', bigscaryfunction())
the bigscaryfunction is always called, even though 'x' is a valid key. 
Is there a "short-circuit" version of get that doesn't evaluate the 
second argument if the first is a valid key? For now I'll code around 
it, but this behavior surprised me a bit...

Dave
If (and this is a big if) you know that the dictionary contains no values that 
evaluate to boolean false, then you can use the short-circuiting 'or' operator:

 >>> def bigscaryfunction():
 ... print "scary"
 ...
 >>> d= globals()
 >>> d.get("key") or bigscaryfunction()
 scary
 >>> d.get("__name__") or bigscaryfunction()
 'LazyDictget'
 >>>
Alternatively, you can just write your own getter function:
 >>> def lazyget(dict_, key, default):
 ... if key in dict_:
 ... return dict_[key]
 ... else:
 ... return default()
 ...
 >>> lazyget(d,"key",bigscaryfunction)
 scary
 >>> lazyget(d,"__name__",bigscaryfunction)
 'LazyDictget'
 >>>
The optimal choice of whether to "look before you leap" i.e., "if key in dict_" 
or simply catch KeyError, depends on the ratio of hits to misses.  Google will 
turn up some experimental data on this, but, I seem to recall that if more than 
10% attempts are misses, then LBYL is faster, because raising the exception is slow

Michael
--
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Steven Bethard
Bill Mill wrote:
On 9 Mar 2005 10:05:21 -0800, [EMAIL PROTECTED]
<[EMAIL PROTECTED]> wrote:
Maybe this can help:
value = d.get('x', lambda: bigscaryfunction())

def test(): print 'gbye'
...
d = {}
z = d.get('x', lambda: test())
z
 at 0x008D6870>
So this seems to be merely an obfuscation of:
z = d.get('x', test)
z

I just wanted to ask, am I missing something?
Nope that looks right.  See "Overuse of lambda" in 
http://www.python.org/moin/DubiousPython for discussion of exactly this 
mistake.

STeVe
--
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Reinhold Birkenfeld
Dave Opstad wrote:
> In this snippet:
> 
> d = {'x': 1}
> value = d.get('x', bigscaryfunction())
> 
> the bigscaryfunction is always called, even though 'x' is a valid key. 
> Is there a "short-circuit" version of get that doesn't evaluate the 
> second argument if the first is a valid key? For now I'll code around 
> it, but this behavior surprised me a bit...

Well, if the dict only contains ints, here is a dirty hack (but don't
use it instead of the try/except approach):

class Littletinyproxy:
def __int__(self):
return bigscaryfunction()

d = dict(x=1)
value = int(d.get('x', Littletinyproxy()))


Reinhold
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Kent Johnson
F. Petitjean wrote:
Le Wed, 09 Mar 2005 09:45:41 -0800, Dave Opstad a écrit :
Is there a "short-circuit" version of get that doesn't evaluate the 
second argument if the first is a valid key? For now I'll code around 
it, but this behavior surprised me a bit...
def scary():
print "scary called"
return 22
d = dict(x=1)
d.get('x', lambda *a : scary())
# print 1
d.get('z', (lambda *a : scary())())
scary called
22
So you have to change the code at the point of call depending on whether the requested value is in 
the dict? ;)

If you can get this to work I'm sure we can find other applications for such 
'smart code' :-)
Kent
--
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Bill Mill
On 09 Mar 2005 18:13:01 GMT, F. Petitjean <[EMAIL PROTECTED]> wrote:
> Le Wed, 09 Mar 2005 09:45:41 -0800, Dave Opstad a écrit :
> > In this snippet:
> >
> > d = {'x': 1}
> > value = d.get('x', bigscaryfunction())
> >
> > the bigscaryfunction is always called, even though 'x' is a valid key.
> > Is there a "short-circuit" version of get that doesn't evaluate the
> > second argument if the first is a valid key? For now I'll code around
> > it, but this behavior surprised me a bit...
> def scary():
> print "scary called"
> return 22
> 
> d = dict(x=1)
> d.get('x', lambda *a : scary())
>
> # print 1
> d.get('z', (lambda *a : scary())())
> scary called
> 22

but:

>>> d.get('x', (lambda *a: test())())
test called
1

So how is this different than d.get('x', test()) ?

Peace
Bill Mill
bill.mill at gmail.com
--
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Bill Mill
On 9 Mar 2005 10:05:21 -0800, [EMAIL PROTECTED]
<[EMAIL PROTECTED]> wrote:
> Maybe this can help:
> 
> value = d.get('x', lambda: bigscaryfunction())

>>> def test(): print 'gbye'
...
>>> d = {}
>>> z = d.get('x', lambda: test())
>>> z
 at 0x008D6870>

So this seems to be merely an obfuscation of:

>>> z = d.get('x', test)
>>> z


I just wanted to ask, am I missing something?

Peace
Bill Mill
bill.mill at gmail.com
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread F. Petitjean
Le Wed, 09 Mar 2005 09:45:41 -0800, Dave Opstad a écrit :
> In this snippet:
> 
> d = {'x': 1}
> value = d.get('x', bigscaryfunction())
> 
> the bigscaryfunction is always called, even though 'x' is a valid key. 
> Is there a "short-circuit" version of get that doesn't evaluate the 
> second argument if the first is a valid key? For now I'll code around 
> it, but this behavior surprised me a bit...
def scary():
print "scary called"
return 22

d = dict(x=1)
d.get('x', lambda *a : scary())
# print 1
d.get('z', (lambda *a : scary())())
scary called
22

First (wrong) version :
d.get('z', lambda *a : scary())
 at 0x40598e9c>
> 
> Dave
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread bearophileHUGS
Maybe this can help:

value = d.get('x', lambda: bigscaryfunction())

Bearophile

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Bill Mill
Dave,

On Wed, 09 Mar 2005 09:45:41 -0800, Dave Opstad <[EMAIL PROTECTED]> wrote:
> In this snippet:
> 
> d = {'x': 1}
> value = d.get('x', bigscaryfunction())
> 
> the bigscaryfunction is always called, even though 'x' is a valid key.
> Is there a "short-circuit" version of get that doesn't evaluate the
> second argument if the first is a valid key? For now I'll code around
> it, but this behavior surprised me a bit...

There is no short-circuit function like you're asking for, because
it's impossible in python. To pass an argument to the 'get' function,
python evaluates the bigscaryfunction before calling 'get'.

(I believe this means that python doesn't have "lazy evaluation", but
the language lawyers may shoot me down on that. Wikipedia seems to say
that it means python doesn't have "delayed evaluation").

Here are two ways to do what you want:

if 'x' in d: value = d['x']
else: value = bigscaryfunction()

or:

def sget(dict, key, func, *args):
if key in dict: return key
else: return func(*args)

sget(d, 'x', bigscaryfunction)

Both methods are untested, but should work with minor modifications.

Peace
Bill Mill
bill.mill at gmail.com
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Peter Hansen
Dave Opstad wrote:
In this snippet:
d = {'x': 1}
value = d.get('x', bigscaryfunction())
the bigscaryfunction is always called, even though 'x' is a valid key. 
Is there a "short-circuit" version of get that doesn't evaluate the 
second argument if the first is a valid key? For now I'll code around 
it, but this behavior surprised me a bit...
try:
value = d['x']
except KeyError:
value = bigscaryfunction()
get() is just a method, and arguments to methods are always
evaluated before being passed to the method, so the short
answer is "no, there is no 'version' of get() that will do
what you want".
-Peter
--
http://mail.python.org/mailman/listinfo/python-list


Is there a short-circuiting dictionary "get" method?

2005-03-09 Thread Dave Opstad
In this snippet:

d = {'x': 1}
value = d.get('x', bigscaryfunction())

the bigscaryfunction is always called, even though 'x' is a valid key. 
Is there a "short-circuit" version of get that doesn't evaluate the 
second argument if the first is a valid key? For now I'll code around 
it, but this behavior surprised me a bit...

Dave
-- 
http://mail.python.org/mailman/listinfo/python-list