1

I have a class and a method:

class Demo(dict):

  def foo(self, key):
     bar = self[key]
     foo(bar, key)

Class Demo accepts a dict as an argument
From app.py I'm calling Demo as:

data = { 'a': { 'a' : 123 } }

Demo(data).foo('a')

My question is, how do I pass the newly formed dictionary bar = self[key] as an argument to foo() while recursing?

Should I use this instead ?:

class Demo():

  def foo(self, data, key):
     bar = data[key]
     foo(bar, key)

Is there any other better approach?

8
  • @Carcigenicate That would certainly help. I'll try it. Thanks! Commented Oct 20, 2019 at 19:20
  • At the very least, you have to write Demo.foo(bar, key), since you don't want a global foo, but the class attribute by that name. Commented Oct 20, 2019 at 19:22
  • It's also not clear from this example alone why foo isn't a static method or a regular function. Commented Oct 20, 2019 at 19:24
  • Were you expecting your class to take dict as an argument or did you mean to inherit from dict as you do above? Commented Oct 20, 2019 at 19:24
  • @Sayse I'm expecting the class to take dict as an argument Commented Oct 20, 2019 at 19:32

4 Answers 4

3

You could use an inner recursive function instead:

def foo(self, key):
    def inner(new_d):
        bar = new_d[key]
        inner(bar)

    inner(self)  # Or whatever you want to be the initial value

Note how it formed a closure over key so that doesn't need to be passed constantly. It can just be accessed from the outer scope.

Of course this function doesn't really make much sense though since it will recurse forever, so I'm assuming this is a stripped down example.

Sign up to request clarification or add additional context in comments.

1 Comment

Using closure seems a great idea. I will definitely try this. Thanks a lot!
2

It IS possible to do what you want, although I don't know if it's the best solution. It really depends on what you're trying to accomplish.

The following code, recurses the way you want. The advantage is (if you want it) that the self.data parameter in the root class (self) changes throughout the recusion. This is good is you WANT that data to change (for example for later access to the changed data by another method later.)

class Demo(dict):
    def __init__(self, data):
        self.data = data

    def foo(self, key):
        try:
            self.data = self.data[key]
            return self.foo(key)
        except:
            return self.data

data = { 'a': { 'a' : 123 } }

print(Demo(data).foo('a'))

If you DON'T want the self.data to be permanently changed, you should use the second method, were data and key are passed into the function together, and do not affect the self.data... or the other answer (about inner recursive function by @Carcigenicate)

Comments

1

Your foo method needs to be called on an instance of Demo, not by itself. In both versions of your code, calling foo without looking it up in something (probably an instance) is an error.

Perhaps you want:

def foo(self, key):
    obj = Demo(self[key])
    obj.foo(key)

This will work for as long as your data has nested dictionaries under the same key. It will fail when self[key] doesn't return a dictionary. Presumably you want to have a base case to handle that:

def foo(self, key):
    value = self[key]  # you might want a further base case to handle the key not existing at all!
    if not isinstance(value, dict):
        pass           # if you have something to do for the base case, do it here
    else:              # recursive case
        obj = Demo(value)
        obj.foo(key)

Now, this class is a bit silly, it copies lots of stuff just so that you can have a method that runs on a dict. A much more sensable approach would get rid of the class and just use a recursive function with two arguments, and you'd have no need for creating obj in the recursive case:

# this foo is a top-level function, not part of a class!
def foo(data, key):  # no self argument any more
    value = data[key]
    ...
    foo(value, key)  # recursive call is simpler now

1 Comment

The second approach without the class would be much cleaner. Thank you!
1

You should instantiate a new instance of the same class with the sub-dict to recursively traverse down the dict with the same key:

class Demo(dict):
    def foo(self, key):
        if isinstance(self[key], dict):
            return self.__class__(self[key]).foo(key)
        return self[key]

so that:

data = {'a': {'a': 123}}
print(Demo(data).foo('a'))

outputs:

123

Demo: https://repl.it/@blhsing/PassionateOddAssembly

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.