3

Say, I have a dic like this

my_dictionary = {'a':1,'c':5,'b':20,'d':7}

Now, I want to do this with my dic:

if my_dictionary['a'] == 1 and my_dictionary['d'] == 7:
    print my_dictionary['c']

This looks ridiculous because I am typing my_dictionary 3 times!

So is there any syntax which would allow me to do something like this:

within my_dictionary:
    if a == 1 and d == 7:
        print c

This would actually work if I didn't have anything more (in this case b) in my dic:

def f(a,d,c):
    if a == 1 and d == 7:
        print c 

f(**my_dictionary)
Pekka
  • 2,348
  • 2
  • 21
  • 33
  • My understanding is that dictionaries are generally for "unrelated items." But in your case c is related to a and d. Does it need to be a dictionary? Will you always lookup 2 values and return a third or will you lookup n values? – Charlie Jul 28 '15 at 12:20

3 Answers3

4

You can change your function to

def f(a,d,c,**args):
    if a == 1 and d == 7:
        print c

then it will work even if you have other items in the dict.

yangjie
  • 6,619
  • 1
  • 33
  • 40
3

You can use operator.itemgetter to minimize multiple indexing :

>>> if operator.itemgetter('a','d')(my_dictionary)==(1,7):
...      print operator.itemgetter('c')(my_dictionary)

And you can use it in a function :

>>> def get_item(*args):
...   return operator.itemgetter(*args)(my_dictionary)
... 
>>> 
>>> if get_item('a','d')==(1,7):
...      print get_item('c')
... 
5
Mazdak
  • 105,000
  • 18
  • 159
  • 188
2

To answer

So is there any syntax which would allow me to do something like this:

within my_dictionary:
if a == 1 and d == 7:
    print c

You can subclass dict so that it has with magic methods. To do this, the class must have __enter__ and __exit__ methods. You could then export the keys to the local scope of the with statement and clean them up with the exit method.

Using this answer I was able to create a subclass that did so:

import inspect
import ctypes

locals_to_fast = ctypes.pythonapi.PyFrame_LocalsToFast
locals_to_fast.restype = None
locals_to_fast.argtypes = [ctypes.py_object, ctypes.c_int]

class WithDict(dict):
    def __enter__(self):
        frame = self.get_frame()
        for k,v in self.iteritems():
            frame.f_locals[str(k)] = v
            locals_to_fast(frame, 1)

    def __exit__(self, exc_type, exc_value, traceback):
        frame = self.get_frame()
        for k in self.keys():
            del frame.f_locals[str(k)]

    def get_frame(self):
        return inspect.getouterframes(inspect.currentframe())[2][0]

A test case using your original example

my_dictionary = WithDict({'a':1,'c':5,'b':20,'d':7})
with my_dictionary:
    if a == 1 and d == 7:
        print c

prints 5

The variables get deleted when the with statement completes

Community
  • 1
  • 1
muddyfish
  • 3,530
  • 30
  • 37
  • Thanks! This seems very useful info. I am not familiar with `with` , `__exit__` and `__enter__` and for my particular problem this is probably too much like killing bees with nuclear missiles. Nevertheless seems to be something I need to take a look at. – Pekka Jul 28 '15 at 12:47
  • Yeah, I was thinking that as I was writing it, it was a nice excersise anyway. You could make it (even more?) nasty by monkey patching `dict` and using bytecode manipulation so you could literally use the {} syntax but that would really be like using nukes! – muddyfish Jul 28 '15 at 12:53