3

I have python 3 code that is not working as expected:

def addFunc(x,y):
    print (x+y)

def subABC(x,y,z):
    print (x-y-z)

def doublePower(base,exp):
    print(2*base**exp)

def  RootFunc(inputDict):
    for k,v in inputDict.items():
        if v[0]==1:
            d[k] = addFunc(*v[1:])
        elif v[0] ==2:
            d[k] = subABC(*v[1:])
        elif  v[0]==3:
            d[k] = doublePower(*v[1:])


d={"s1_7":[1,5,2],"d1_6":[2,12,3,3],"e1_3200":[3,40,2],"s2_13":[1,6,7],"d2_30":[2,42,2,10]}
RootFunc(d)

#test to make sure key var assignment works
print(d)

I get:

{'d2_30': None, 's2_13': None, 's1_7': None, 'e1_3200': None, 'd1_6': None}

I expected:

{'d2_30': 30, 's2_13': 13, 's1_7': 7, 'e1_3200': 3200, 'd1_6': 6}

What's wrong?

Semi related: I know dictionaries are unordered but is there any reason why python picked this order? Does it run the keys through a randomizer?

Matthew Adams
  • 9,426
  • 3
  • 27
  • 43
fozbstuios
  • 373
  • 4
  • 8
  • 17

2 Answers2

12

print does not return a value. It returns None, so every time you call your functions, they're printing to standard output and returning None. Try changing all print statements to return like so:

 def addFunc(x,y):
     return x+y

This will give the value x+y back to whatever called the function.

Another problem with your code (unless you meant to do this) is that you define a dictionary d and then when you define your function, you are working on this dictionary d and not the dictionary that is 'input':

def  RootFunc(inputDict):
    for k,v in inputDict.items():
        if v[0]==1:
            d[k] = addFunc(*v[1:])

Are you planning to always change d and not the dictionary that you are iterating over, inputDict?

There may be other issues as well (accepting a variable number of arguments within your functions, for instance), but it's good to address one problem at a time.


Additional Notes on Functions:

Here's some sort-of pseudocode that attempts to convey how functions are often used:

def sample_function(some_data):
     modified_data = []
     for element in some_data:
          do some processing
          add processed crap to modified_data
     return modified_data

Functions are considered 'black box', which means you structure them so that you can dump some data into them and they always do the same stuff and you can call them over and over again. They will either return values or yield values or update some value or attribute or something (the latter are called 'side effects'). For the moment, just pay attention to the return statement.

Another interesting thing is that functions have 'scope' which means that when I just defined it with a fake-name for the argument, I don't actually have to have a variable called "some_data". I can pass whatever I want to the function, but inside the function I can refer to the fake name and create other variables that really only matter within the context of the function.

Now, if we run my function above, it will go ahead and process the data:

 sample_function(my_data_set)

But this is often kind of pointless because the function is supposed to return something and I didn't do anything with what it returned. What I should do is assign the value of the function and its arguments to some container so I can keep the processed information.

my_modified_data = sample_function(my_data_set)

This is a really common way to use functions and you'll probably see it again.


One Simple Way to Approach Your Problem:

Taking all this into consideration, here is one way to solve your problem that comes from a really common programming paradigm:

def  RootFunc(inputDict):
    temp_dict = {}
    for k,v in inputDict.items():
        if v[0]==1:
            temp_dict[k] = addFunc(*v[1:])
        elif v[0] ==2:
            temp_dict[k] = subABC(*v[1:])
        elif  v[0]==3:
            temp_dict[k] = doublePower(*v[1:])
    return temp_dict


  inputDict={"s1_7":[1,5,2],"d1_6":[2,12,3,3],"e1_3200":[3,40,2],"s2_13":[1,6,7],"d2_30"[2,42,2,10]}
  final_dict = RootFunc(inputDict)
erewok
  • 7,555
  • 3
  • 33
  • 45
  • Your solution does work. However I tried changing the part where I assign values (d[k]) to a variable with the value of inputDict. Items( your suggestion was what I wanted as my previous code would've had me change d[k] to foo[k] every time I wanted to use a new dictionary. This did not change the d dictionary. How do I change the table while using your modular approach? – fozbstuios Aug 05 '13 at 05:16
  • I think what you're describing is a new problem. You pass `inputDict` into the function, then you do some stuff with `inputDict` and then nothing happens after that. The reason for this is that, again, you aren't returning anything. Thus, at the end you should `return` the dictionary that has been modified. That's not the whole picture, however, because something would need to capture that value. Typically it works like this: functions process some data and give back the processed stuff with `return`. You then call the functions like this: `some_capturing_variable=RootFunc(d)` – erewok Aug 05 '13 at 05:23
  • Ok I think I'm starting to get it. However returning inputDict won't do anything because I am modifying inputDict.items(). Returning this doesn't do anything either. When I return either one any print d I get the original value of d – fozbstuios Aug 05 '13 at 05:30
  • 1
    It's also generally a bad idea to modify something that you are iterating over. You will usually create an empty container to hold the values you want, iterate over the input data, and while iterating and processing, you will add the processed data to your container. Check out my notes on functions and they may be useful. – erewok Aug 05 '13 at 05:32
  • Where are these notes? Sorry to be such a pest! And I take it there is no way to get around the return inputDict.items not changing anything problem? – fozbstuios Aug 05 '13 at 05:37
  • inputDict.items is not something you would return. If you are really going to change `inputDict` while inside your function, then you would return the whole thing, `inputDict`. Notes are at bottom of my post. – erewok Aug 05 '13 at 05:43
  • Finally got it working thanks to you! Any cons to d = RootFunc(d)?This is recursion right? – fozbstuios Aug 05 '13 at 06:04
  • No cons, really and that is not recursion. Recursion is when a function calls itself *inside* the function. – erewok Aug 05 '13 at 06:07
2

As erewok stated, you are using "print" and not "return" which may be the source of your error. And as far as the ordering is concerned, you already know that dictionaries are unordered, according to python doc at least, the ordering is not random, but rather implemented as hash tables.

Excerpt from the python doc: [...]A mapping object maps hashable values to arbitrary objects. Mappings are mutable objects. There is currently only one standard mapping type, the dictionary. [...]

Now key here is that the order of the element is not really random. I have often noticed that the order stays the same no matter how I construct a dictionary on some values... using lambda or just creating it outright, the order has always remained the same, so it can't be random, but it's definitely arbitrary.

Amit
  • 482
  • 4
  • 10