0

I have a function here that returns itself if a dictionary of dictionaries is detected (which will always be the case). I know that as of right now, my function runs until is errors out and hits a recursion depth limit. Would anyone know how I could properly pop or delete an item from the dictionary if k != numero . I have tried popping k off of my_dict in the else statement but that produces an AttributeError saying strings do not have that ability. I ran the code through pycharm debugger and it will show 'four' as k and 'five' as v. Both of these are strings but they are present key/values in the dict so I am confused.

Here is my code.

my_dict = {'one': {'two': 'three', 'four': 'five', 'six': 'seven'}}
k = ''
numero = 'six'

def find_location(d):
    global key
    for k, v in d.iteritems():
        if isinstance(v, dict):
            key = find_location(v)
        elif k == numero:
                print v
                print k
        else:
            return find_location(d)
scharette
  • 9,437
  • 8
  • 33
  • 67
UCProgrammer
  • 517
  • 7
  • 21
  • @scharette I'll see if it helps. I feel like I looked at 20 different posts and still didn't get the answer so I just posted – UCProgrammer Jul 24 '18 at 12:01
  • If you feel like it is completely different, don't explain your errors. Instead include the stacktrace so we can see what are the errors that are actually returned. _hits a recursion depth limit_, _produces an AttributeError saying strings do not have that ability._ is not very helpful for people trying to help you. – scharette Jul 24 '18 at 12:03
  • @scharette All it does is return find_location(d) until it hits RunTimeError: maximum recursion depth exceeded while calling a python object. This is obvious because I'm not modifying the initial value, which is a dict, at all in this function. I'd rather not modify the dict if I had the choice. Calling something like next() would be nice here, but it returns the same error – UCProgrammer Jul 24 '18 at 12:08
  • Your else statement returns d and every time your reach the second recursion depth, it keeps getting their. What is the expected behavior. – T.Nel Jul 24 '18 at 12:13
  • 1
    If you are just trying to remove an item from a dict, see this https://stackoverflow.com/questions/5844672/delete-an-element-from-a-dictionary – T.Nel Jul 24 '18 at 12:15
  • @T.Nel I would like that else statement to contain some code that either returns the next key:value pair in the dict or deletes that current key:value pair so I can return to the top of the function and see if k == numero. Then I want to print v and k. Right now, the same dict keeps getting returned and it keeps looking at that same key:value pair, thus being the reason for recursion error – UCProgrammer Jul 24 '18 at 12:17
  • @T.Nel Thank you. That helped. I believe I was foolishly using del k[v] before and not del d[k]. sorry for the trouble – UCProgrammer Jul 24 '18 at 12:21

1 Answers1

1

By using del command instead of pop I managed to get the result you described. This is the script I run with some modifications because I used python3.

my_dict = {'one': {'two': 'three', 'four': 'five', 'six': 'seven'}}
k = ''
numero = 'six'

def find_location(d):
    global key
    for k, v in d.items():
        if isinstance(v, dict):
            key = find_location(v)
        elif k == numero:
                print(v)
                print(k)
        else:
            print('Deleting ' + str(k) + ':' + str(d[k]))
            del d[k]
            print(d)
            return find_location(d)

    print(d)

find_location(my_dict)

Let me know how it runs for you.

------update

If I understood correctly I think I found the problem in your code. When you want to call a function recursively, you must do it with return command, something that you don't do in key = find_location(v). The below code works.

my_dict = {'one': {'two': 'three', 'four': 'five', 'six': 'seven'}}
k = ''
numero = 'six'

def find_location(d):
    global key
    for k, v in d.items():

        if isinstance(v, dict):
            return find_location(v)
        elif k == numero:
                print(v)
                print(k)

                k = 'your-assigned-value'
                print(k)
                return k
        else:
            print('Deleting ' + str(k) + ':' + str(d[k]))
            del d[k]
            return find_location(d)

    return k



result = find_location(my_dict)

print('result = ' + str(result)) 

If you don't use return Python automatically makes the result of a functions's return equal to null. Hope this helps.

  • It runs well. I have one question though. Is there a way to just break out of the code once k == numero true? It prints everything twice when ran because it will find k == numero but 'two':'three' is still left in the dict so it will remove that and then iterate over 'six':'seven' a second time. – UCProgrammer Jul 24 '18 at 12:40
  • By making the function `return d` inside the`elif k == numero:` case, it will break the recursion and return the final dictionary. However this will work only if the `numero` key is in the last position, otherwise it will return upon it's first occurance. I don't know what are you trying to achieve exactly. – Marios Karatisoglou Jul 24 '18 at 12:58
  • I have a counter that I implemented and once k == numero, that counter goes from 0 to 1. Then I have a conditional that sees if the counter is 1 and if it is, it breaks. Once it breaks it should reach my final return statement. My final return statement will return a variable that I assigned to k when k == numero. Now, that return statement executes but the for loop continues to go! My indentation with return statements is proper. No clue what is happening – UCProgrammer Jul 24 '18 at 13:03
  • What below code? – UCProgrammer Jul 24 '18 at 13:42
  • I updated my first post check it out – Marios Karatisoglou Jul 24 '18 at 14:32
  • Also the `counter == 1` statement that you said you have as a final statement, means **this is the first occurence**. This is not necessary, just `return` immediately like I do in my code. – Marios Karatisoglou Jul 24 '18 at 14:39
  • I will look in a bit. thanks. I'm testing an alternative without recursion. I have to declare a few variables as None before I loop through them, which I'd imagine is not good practice, but I believe this may work – UCProgrammer Jul 24 '18 at 14:41