3

Ok so i've build my own variable handler which has a __getitem__ function for use when accessing data via data[key], it works great except for when trying to access a link of items:

data["key"]["subkey"]


def __getitem__(self, key, **args):
    print key
    ...
    return self.dict[key]

When trying to access a subkey that doesn't exist, Python simply returns a KeyError without printing "subkey", why is this and how can I get Python to print out what I'm actually trying to get?

I know that I've probably misunderstood the mechanics but is there a way to emulate a dictionary AND follow the string of data that's being requested? Mainly so I can dynamically log the missing variables in a dictionary flow...

This obviously works (but it's not the native syntax that I like):

data["key:subkey"]

def __getitem__(self, key, **args):
    for slice in key.split(':'):
        print key
    ...

The goal is to emulate the following,

Works:

data = {'key' : {'subkey' : 1}}
print data["key"]["subkey"]

Will not work, but I want to catch the exception within __getitem__ and then create the missing key automatically or just log the missing subkey:

data = {'key' : {}}
print data["key"]["subkey"]

Solution:

class Var():
    def __init__(self):
        self.dict = {'test' : {}}
    def __getitem__(self, var, **args):
        print ':',var
        if var in self.dict:
            v = Var(self.dict[var])
            return v

print vHandle['test']['down']

Output:

: test

: down

None

Community
  • 1
  • 1
Torxed
  • 22,866
  • 14
  • 82
  • 131
  • Am I missing something here, or did this not deserve a downvote at all? Could the downvoter explain themselves? – Polynomial Feb 21 '12 at 13:25
  • What is the type of `data`? What is the type of `data["key"]`? You probably need to show more code -- otherwise all we can do is guess. (Not my downvote) – Sven Marnach Feb 21 '12 at 13:27
  • 2
    No, you can't do it directly (you can by returning a wrapped object doing the same thigns). Think of it this way: `_ = data['key']` followed by `_['subkey']`. You could alternatively have `data['key', 'subkey']` (tuple keys) if that was a valid way of accessing the data. – Chris Morgan Feb 21 '12 at 13:28
  • Ok so there's no way to emulate/replace the excisting dictionary way of accessing data without toubles, list or split()? – Torxed Feb 21 '12 at 13:31
  • 1
    @Torxed: you can have `data['key', 'subkey]` and it will call `__getitem__` with `key == ('key', 'subkey')`. That's neater than using a string and splitting on colon. But if you return a wrapped object with `__getitem__` defined, it can be done. I'd prefer the tuple-keys version if it were feasible for your use case (it may or may not be) – Chris Morgan Feb 21 '12 at 13:34
  • 1
    Formatting note: you can get magic method names (leading and trailing underscores) to be formatted correctly by putting them in code with the backtick (preferred), or by prefixing the first underscore with a backslash to escape it. – Chris Morgan Feb 21 '12 at 13:35
  • Heh, thx Chris! I'm still a bit new here and trying to learn the formats. My accepted answer works like a charm! :) – Torxed Feb 21 '12 at 13:38

2 Answers2

5

The fact is that when Python encounters an expression such as data["key"]["subkey"], what is done internally is (data["key"])["subkey"]. That is, the first part of the expression is resolved: the retrievalof the item "key" from the object "data". Then, Python tries do call __getitem__ on the resulting object of that expression. If such resulting object does not have a __getitem__method itself, there is your error.

There are two possible workarounds there: you should either work with "tuple indexes" - like data["key", "subkey"](and then test on your __getitem__ method wether you got a tuple instance as the key) - or make __getitem__ return an specialized object that also features a __getitem__ method - even if all it does is to log the requested keys.

jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • So that's how it works, i just assumed that python would automaticly call __getitem__ through the same variable instance again after the first key, i'm guessing i have to return a second instance of my variable handle so that __getitem__ exists for the second call. Thank you! – Torxed Feb 21 '12 at 13:36
4

Remember: tmp = foo['bar']['baz'] is the same as tmp = foo['bar']; tmp = tmp['baz']

So to allow arbitrary depths your __getitem__ method must return a new object that also contains such a __getitem__ method.

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • i'm guessing i have to return a second instance of my variable handle from within the "variable handler" so that __getitem__ exists for the second call as well then. Thank you! – Torxed Feb 21 '12 at 13:37