Reputation: 1852
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?
Upvotes: 1
Views: 715
Reputation: 106512
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
Upvotes: 1
Reputation: 104712
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
Upvotes: 1
Reputation: 45745
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.
Upvotes: 3
Reputation: 2492
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)
Upvotes: 2