5

I've been learning Python for about 2 months now (Started with Learn Python The Hard Way, now reading Dive Into Python), and within both books, I still seem to be confused over this one bit of code.

Lets just take the default code that Dive Into Python uses as an example:

def buildConnectionString(params):
    """Build a connection string from a dictionary of parameters.


    Returns string."""
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

if __name__ == "__main__":
    myParams = {"server":"mpilgrim",
                "database":"master",
                "uid":"sa",
                "pwd":"secret"
               }

print buildConnectionString(myParams)

How does the function buildConnectionString with the argument (params) know to get its data from the variable myParams? Or params.items(), too within the return line? Wouldn't the argument in buildConnectionString need to be set as buildConnectionString(myParams) in order for it to read properly? How can you set the variable of your data to myParams, but have the argument of your function be params and have it read? How does it know to read myParams as params?

And is there a reason behind not naming your variable params, or vice versa naming your argument in your function myParams? It's just been extremely confusing seeing the argument set as one word, and then having the variable named something completely different, but having the function still be able to read your code, even when the argument name is different from your variable with the data you're printing from.

2
  • Thank you for the edit. I didn't realize I had a notification requesting that I edit something.
    – Kevin
    Commented Jul 25, 2012 at 11:29
  • 1
    Shouldn't this go to SO?
    – H2CO3
    Commented Jul 28, 2012 at 22:30

8 Answers 8

7

It's not about Python.

But nevertheless, to answer you straightly. Lets say you have a function:

def doSomethingWithParmas(params):
    params.doSomething()

Now you can call it later on with:

print doSomethingWithParams(myParams)

or/and

print doSomethingWithParams(yourParams)

It's how functions work, you can call it with whatever params you like, all that function cares, is that they are some kind of params that it can handle.

EDIT: A remark: I have never coded a line of Python in my life.

4
  • so let's say we do something like this <br> def doSomethingWithParams(params): params.doSomething() x = "whatever" y = "whatever"
    – Kevin
    Commented Jul 25, 2012 at 11:54
  • I was trying to type code in the comment, and it wasn't allowing me..than it wouldn't allow me to edit because of the 5 minute rule..what I wanted to say was thank you for your response.
    – Kevin
    Commented Jul 25, 2012 at 12:00
  • @kevin and the reason this is necessary is that the function migth be put in a library and used by someone else - so it's important that the name of the params is just a token fro whatever is passed in Commented Jul 28, 2012 at 21:21
  • 2
    That edit is wrong. You have now coded 4 lines of Python in your life.
    – Jordan
    Commented Jul 29, 2012 at 1:22
5

Maybe it would be clearer if the arguments were differently named?

def buildConnectionString(placeholder_for_whatever_is_passed_in):
    return ";".join(["%s=%s" % (k, v) for k, v in placeholder_for_whatever_is_passed_in.items()])

if __name__ == "__main__":
    what_I_actually_pass in = { "server":"mpilgrim",
                                "database":"master",
                                "uid":"sa",
                                "pwd":"secret"   } 

print buildConnectionString(what_I_actually_pass_in)
1

If we take a look at

def buildConnectionString(params):
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

params is a locally-scoped variable. It's not referring to any other variables in your code, it is the name for the variable you pass into your function. What this means is that you can pass any variable into buildConnectionString() without having to know in advance what you are passing in.

Regarding naming myParams vs params there is no real reason. You could just as easily name it params if it helps you keep track of things. But what happens when you need to keep two sets of params variables? This is why you pass variables into your function rather than referencing global (defined outside of a function) variables. You could have written that function as

myParams = {"server":"mpilgrim",
            "database":"master",
            "uid":"sa",
            "pwd":"secret"
           }

def buildConnectionString():
    return ";".join(["%s=%s" % (k, v) for k, v in myParams.items()])

print buildConnectionString(myParams)

Doing it that way means you can only print myParams. But if you define myOtherParams you couldn't print it at all. You just have to keep in mind that any variables defined inside of the parentheses is only a copy of the variable you pass into it, not the original variable itself.

1

First, you need to understand what functions are used for. You might say, that a function provides a service: It does something for you.

Functions

  • Provide a service
  • don't know you exist

A printer for example is some kind of a service: It prints documents for you, you don't have to do it yourself. If you provide the printer with the necessary information (the parameters), the printer will happily do its job.

The printer does not know what data it will receive, otherwise, it wouldn't need a parameter. The parameter is the "unknown" that is needed to perform the service.

def my_function(a, b):
    pass

This provides a service (or function) that wants two pieces of information from you. Once it has this information, it needs to be able to refer to it somehow. The notation (a, b) simply means that whatever you give it as first "information", will accessible from the name a and what you pass second will be accessible from the name b.

When you actually call the function (i.e. tell the printer to actually print something), you need to fill in these gaps of knowledge like so:

my_function(data_that_i_know, other_data_that_i_know)

Your questions

How does the function buildConnectionString with the argument (params) know to get it's data from the variable myParams?

It doesn't. Does my printer know I am going to print a document relating to programming tomorrow? No. Tomorrow, I will send the information to my printer, which it will then happily print. The printer does not even know I exist.

Similarly, you "send" (pass) the data (myParams) to your function with the following expression:

buildConnectionString(myParams)

At some other point in your program, you may wish to execute your function with different data. Similar to the printer, the function doesn't know who will call it, or when it will be called, or with what data it will be called.

Or params.items(), too within the return line?

The function, once executed, has received some data so it can do its job. This will execute a function called items() on whatever has been given the function to work with.


An example function

I want to create my own service, that can calculate the square of a number. This implies, that it needs to be given a number in order to work. After all, you can't square nothing, can you?

The function does not know, which number it will be given. However, in order to be able to multiply this number, we need to be able to refer to it somehow, hence, we give it a name: x.

def square(x):
    return x * x

This defines a function called square that needs to be given one piece of data (the x).

I can now use this function to square a number:

>>> print square(2) # "Please square this number 2 for me"
4

Within the function, x now refers to the value 2.

But I could also have called the function with the number 3:

>>> print square(3) # "Please square this number 2 for me"
9

I could have chosen the name two instead of x for my function. But that would be misleading: The value does not have to be 2, it can be whatever I wish it to be.


And is there a reason behind not naming your variable params, or vice versa naming your argument in your function myParams?

Names in programming can be chosen arbitrarily, as long as they are not reserved by the language (these are called keywords).

Usually, you will name your variables whatever makes sense in that context. For instance, in code about geometric objects, my local variable may be named area which I will then square using the square() function. In code about a car I may have a variable named weight on the otherhand. I am sure you will agree that I being able to call square with square(weight) and square(area) conveys a lot of information.

Would you now change the parameter of square from x to weight_or_area? I hope you wouldn't. What if I was to use the function in connection with lengths? You will have to get used to the fact that parameters and arguments of functions are usually named differently, that is a Good Thing®.

It's just been extremely confusing seeing the argument set as one word, and then having the variable named something completely different, but having the function still be able to read your code, even when the argument name is different from your variable with the data you're printing from.

It is important to understand, that the function does not read your code. It has no idea it even exists. This brings us back to the printer analogy: Does it know you or I exist? Not, it's there to perform a job, no questions asked. The same thing applies to functions: They are there to do our bidding. They do not act on their own and "read code" to see where they are referenced.

1

You're right to wonder why this symbol doesn't seem to mean anything to the rest of the file, but its spelling isn't its only attribute. Consider its positioning.

The confusion lies in trying to equate the parameter name and the argument name. You are right, there is no connection between the names as such. But if you saw a Python error message due to a missing argument from within a parentheses, you might see the terminology "positional argument". It's the positioning of the argument in the parentheses following the call of function x that identifies the argument as corresponding to the parameter from the def statement of the same function.

You wonder why the parameter and argument don't have the same name. The two names have the same position relative to the function name, which is their only connection.

What is meaningful in this function:

print('Say anything.')
nilj = input()
def rabberd(durf):
    print(nilj + ' what?')

rabberd(nilj)

Meaningful to Python: "def", "input" and "print".

Meaningful to the file:

  • rabberd is rabberd
  • nilj is input
  • relative positioning of nilj and durf equate them to each other.
  • durf as a word is arbitrary; only its position is meaningful.
0

You need to read this for a complete understanding of how functions and their parameters work in python: http://docs.python.org/tutorial/controlflow.html#defining-functions

A simple explanation is that the python interpreter matches the first parameter in your function call to the first value in the function definition, the second to the second and so on if the parameters in the function call are not named.

In your example, when you do print buildConnectionString(myParams) as you have done, python assumes you meant print buildConnectionString(params=myParams) which is a fair assumption to make. The value of params can be anything you like but if you mess up the parameter name itself, you will get an error.

This will not give you an error: print buildConnectionString(params=whateveryouwant)

But this will give you an error: print buildConnectionString(wrongparametername=myParams)

0

You’re noticing the difference between parameters and arguments, and also the notion of scope.

A parameter is a name that refers to a value passed into a function. Consider a trivial function definition:

def f(x):
    return x

Here, x is a parameter of f. An argument is the value assigned to a parameter during a function call.

print f(42)

Here, 42 is an argument to f. In a function call, you can think of substituting all the instances of the parameter (name) with the argument (value). So when you write f(42), what the interpreter does is return 42.

Similarly, when you write buildConnectionString(myParams), it is exactly as though you had written:

";".join(["%s=%s" % (k, v) for k, v in {
    "server":"mpilgrim",
    "database":"master",
    "uid":"sa",
    "pwd":"secret" }.items()])

params is replaced with the value of myParams, and the resulting statements are executed.

0

Okay, when I understood you correctly your problem is that you don't know why params inside the function is associated with the dictionary myParams you put into the function, right?

Okay, lets start at the beginning:

When you have the following python code, how does Python know that you can call the upper() method (which makes it all caps) on the variable?

a = "hello"
...
print a.upper() 

a could have been an integer if we wrote a = 1 instead of a = "hello". But as you might have learned already, python is a dynamic language and is able to handle this without defining what a variable should hold in the first place.

Now to your problem with the function. Let's say that we got the following function:

def divide(a,b)
    return a / b

a and b are not only parameters, they are variables. When python sees the line result = divide(4,2) it technically does the following:

""" Create local variables and assign the input values to them """
a = 4
b = 2
result = a / b
""" Because the variables were local they do not exists after the function
    call ended """

If we now try to call this function as divide("hello","world") the program crashes because you cannot use division on strings. So far so good.

So your question can be reduced on the following problem:

myParams = { "foo":"bar", "meow":"purr" }
someOtherVariable = myParams
print someOtherVariable["meow"]

How does Python know that someOtherVariable can be treated as myParams? Because we told it to be the same. And that is exactly what happens when you call your function with myParams. It implicitly makes params = myParams until the end of the function call. This code works because the function assumes that the content of params has the methods you call on it (in this example items()). If it doesn't it crashes. You can try this by calling buildConnectionString(1). It will say that int has no attribute 'items'.

TLDR; Function parameters are like normal variables. Python tries to do with them what you wrote in your function body - if the you call functions on the objects which they don't have your program crashes like it would do when you did the same thing to a normal variable.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.