views:

271

answers:

3

Earlier today I asked a question about passing dictionary values to a function. While I understand now how to accomplish what I was trying to accomplish the why question (which was not asked) was never answered. So my follow up is why can't I

def myFunction(newDict['bubba']):
    some code to process the parameter

Is it simply because the parser rules do not allow this? I Googled for +Python +function +"allowable parameters" and did not find anything useful so I would appreciate any information.

I am oversimplifying what is going on. I have a dictionary that is structured like

myDict={outerkey1:(innerkey1:value,innerkey2:value,. . .innerkeyn:value),outerkey2:(innerkey1:value,innerkey2:value,. . .innerkeyn:value),. . .}

As I said, I know how to do what I wanted-I got a very helpful answer. But I started wondering why

 def myFunction(outerkey,myDict[outerkey]):

gives a syntax error which finely it occurred to me that it has to be a parsing problem.

+5  A: 

Yes, the parser will reject this code.

Parameter lists are used in function definitions to bind identifiers within the function to arguments that are passed in from the outside on invocation.

Since newDict['bubba'] is not a valid identifier, this doesn't make any sense -- you need to provide it as an invocation argument instead of a function parameter, since function parameters can only be identifiers.

Because you seem interested in the formal grammar, here are the relevant parts:

funcdef ::= 
             [decorators] "def" funcname "(" [parameter_list] ")"
              ":" suite

parameter_list ::= 
                 (defparameter ",")*
                (~~"*" identifier [, "**" identifier]
                 | "**" identifier
                 | defparameter [","] )

defparameter ::= 
             parameter ["=" expression]

identifier ::= 
             (letter|"_") (letter | digit | "_")*

In fact, the construct you are trying to use as an identifier is a subscription:

subscription ::= 
             primary "[" expression_list "]"
cdleary
Thanks, this will give some interesting reading later.
PyNEwbie
newDict['bubba'] is not a valid identifier I guess learning how to read the grammar will help with understanding that. When I started down this line I decided it should work because when the function is called newDict['bubba'] references the thing I wanted the function to act on. The solution was to use ** in front of the reference in the call and to use ** in front of a name in the definition as others have described but I didn't understand (and now do only at a superficial level) until your answer. Hopefully when I get bored and read the grammar I will learn more thanks again
PyNEwbie
In Python, identifiers (names for objects) can only have letters, numbers, and underscores in them. If the grammar were to allow `newDict['bubba']` as a symbol that names an object, it would have trouble telling the difference between symbols that name objects and the subscript operation on lists/dictionaries. Plus, if you could use `newDict['bubba']` as an identifier, it'd be confusing, because `newDict` isn't a valid identifier, even though it looks like it's something you could index into.
cdleary
dentifiers (names for objects) can only have letters, numbers, and underscores in them so this was really the crux of my problem today
PyNEwbie
Yep! In an effort to increase readability, Python allows a very limited set of characters in its identifiers.
cdleary
+2  A: 

It looks like you might be confused between the definition of a function and calling that function. As a simple example:

def f(x):
    y = x * x
    print "x squared is", y

By itself, this function doesn't do anything (ie. it doesn't print anything). If you put this in a source file and run it, nothing will be output. But then if you add:

f(5)

you will get the output "x squared is 25". When Python encounters the name of the function followed by actual parameters, it substitutes the value(s) of those actual parameters for the formal parameter(s) in the function definition. In this case, the formal parameter is called x. Then Python runs the function f with the value of x as 5. Now, the big benefit is you can use the same function again with a different value:

f(10)

prints "x squared is 100".

I hope I've understood the source of your difficulty correctly.

Greg Hewgill
No I think I understand the difference I wanted to define my function and then later for key in myDict: result=myFunction(outerKey,myDict[innerKey])As I said I got a good answer I wanted to know why my original approach did not work
PyNEwbie
+2  A: 

You can only pass references to objects.

a = { 'a' : 123, 'b' : [ 1, 2, 3 ] }

def f(dictionary_value):
    dictionary_value.append(4)

f( a['b'] )

Does what you expect. Dictionary element a['b'] is passed "by reference" to the function f which updates the dictionary element.

S.Lott
This is interesting and looks simpler than the solution I worked with today and it works. Cool So Can I have two accepted answers?
PyNEwbie
He is passing a *reference type* (a list). If you were to pass a['a'] in this way, performing dictionary_value += 2 would not affect a['a']. It's important to understand the difference between value and reference types!
cdleary
Everything's a reference. There is no useful distinction between "reference types" and "value types". However, some types are immutable. The immutability makes them look like 'value' types in Java or C++.
S.Lott
Right, but then you have to start explaining identifier binding -- I assume most people come from languages where ideas of "by value" and "by reference" will just click in their mind the right way. I should probably stop doing that. :-)
cdleary
I am coming from SAS learned on the mainframe-what are those :)
PyNEwbie
Data step programming in SAS only has "by value" -- i.e. if you do "x = y;" then x will have a copy of the value of y. You could kind-of get reference semantics in SAS using macro variables: If you do "%let y = 3; %let x = y;" then "%put(" should display "3". And later, "%let y = 7;", "%put(" should then display "7". So x is acting something like a "pointer" to y. But really, it's a concept that doesn't exist in SAS to any meaningful degree.
John Fouhy
Since this is a Python question, SAS features don't really apply very well. Neither to C, C++ or Java features. This question and the related question are fundamental confusion over the essential simplicity and transparency of Python variables.
S.Lott