# Function parameters and naming

**URL:** <https://discuss.python.org/t/function-parameters-and-naming/53604>\
**Category:** Python Help\
**Created:** [May 17, 2024, 4:00pm UTC](https://discuss.python.org/t/function-parameters-and-naming/53604 "2024-05-17T16:00:06Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Juandev](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/juandev/32/14555_2.png) [@Juandev](https://discuss.python.org/u/Juandev)\
**Post date:** [May 17, 2024, 4:00pm UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/1 "2024-05-17T16:00:06Z")

</div>

Do I understand well that `def` function parameters allow the communication of values between the _function scope_ and the rest of the code? So, for example, if I have:

```python
def my_function():
    print("foo")

```

I don’t need to set the `my_function()` param because I don’t need any parameter within `print()`. While if I define something like this:

```python
def greeting(name):
  print(f"Hi, my name is {name}.")
  
greeting("Peter")

```

`{name}` within the `print()` cannot retrieve value outside that function scope so I do have to set greeting parameter?

And why do the function parameter placeholder sometimes differ from variables in or outside the scope? For example, I define:

```python
def outer_function(whatever):
  def inner_function():
    print("Button pressed.")
    print(input_string.get())
  return inner_function

...

input_string = tk.StringVar(value = "test")
entry = ttk.Entry(window, textvariable = input_string)
entry.pack()

...
button = ttk.Button(window, text = "Button 1", command = outer_function(input_string)) 
button.pack()

```

The first run of the `outer_function` does not need to retrieve any values from outside the function scope, and on the second run, just the `inner_function` is performed. So why is there a whatever parameter? Do we somehow use `whatever`?

---

<div class="post-metadata">

**Author:** ![Nineteendo](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nineteendo/32/19122_2.png) [@Nineteendo](https://discuss.python.org/u/Nineteendo)\
**Post date:** [May 17, 2024, 4:32pm UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/2 "2024-05-17T16:32:13Z")

</div>

Hmm, did you intend to use a closure? Otherwise this function only works if `input_string` is a global variable.

```python
def outer_function(input_string):
  def inner_function():
    print("Button pressed.")
    print(input_string.get())
  return inner_function

def main():
    input_string = tk.StringVar(value = "test")
    entry = ttk.Entry(window, textvariable = input_string)
    entry.pack()
    ...
    button = ttk.Button(window, text = "Button 1", command = outer_function(input_string)) 
    button.pack()

main()

```

The inner function can use the parameters of the outer function.

---

<div class="post-metadata">

**Author:** ![kknechtel](https://avatars.discourse-cdn.com/v4/letter/k/e47c2d/32.png) [@kknechtel](https://discuss.python.org/u/kknechtel)\
**Post date:** [May 17, 2024, 11:44pm UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/3 "2024-05-17T23:44:06Z")

</div>

> [@Juandev](#):
>
> Do I understand well

The way you use the terminology is a bit strange, but your understanding seems fine.

> [@Juandev](#):
>
> And why do the function parameter placeholder sometimes differ from variables in or outside the scope?

**Because that’s the point**. When you write a function that has a parameter, you are consciously expecting the calling code to _give you_ the value that the code will work with. Because of this, you _don’t need to know_ what the outside code calls it, because you won’t go looking for it - it’s given to you. You can call it whatever makes sense locally, and use that name to write the code for the function. That also means that _multiple_ other places can use your function, and give it _differently named_ - or even _unnamed_ things:

```python
def my_function(a_value):
    print("I was given", a_value)

print("In one place, I use a different name")
dead_parrot = "a Norwegian Blue"
my_function(dead_parrot)

print("in another place, I use no name")
my_function("lovely spam, wonderful spam")

```

> [@Juandev](#):
>
> For example, I define:

This example is a lot more complicated. But first you should understand that **there is no** “second run” of `outer_function`. Instead, calling `outer_function` **creates a new** `inner_function`; and when the button is pressed, Tkinter will call that separately created `inner_function`.

> [@Juandev](#):
>
> So why is there a whatever parameter? Do we somehow use `whatever`?

Because someone made a mistake when writing the code. 😉 When the `inner_function` runs, it needs to use `input_string`, which is a global. It will always use that name, no matter how we called `outer_function` in the first place; and it will look in the global namespace for that name.

The intended technique looks like this instead:

```python
def outer_function(whatever):
  def inner_function():
    print("Button pressed.")
    print(whatever.get()) # notice this is changed
  return inner_function

```

Now, the `inner_function` will look up the `whatever` name when it runs. But when it was compiled, Python knew “oh, this function is nested, and the other function that it’s nested inside, has its own `whatever` name”. So Python will compile this a little differently. When the `inner_function` runs, it will look for a _closure_ for `whatever` - a special storage area that remembers the locals from the `outer_function` call, even after the `outer_function` has finished running. (And it only creates this storage because it saw the nested function during compilation, and it only creates storage for `whatever`.)

The idea is, when we write

> [@Juandev](#):
>
> ```python
> button = ttk.Button(window, text = "Button 1", command = outer_function(input_string)) 
> button.pack()
> 
> ```

, now the `outer_function` can create a button callback that works with any `tk.StringVar`, not just the `input_string` global. You just have to pass it to `outer_function`, and it sets up this special “binding” for the `inner_function`, that lets it remember which `tk.StringVar` to use when the button is clicked.

So this means we can make multiple `tk.StringVar`s and multiple `ttk.Button`s, and use the same `outer_function` logic to explain how the buttons should work. When we call `outer_function`, we say which `StringVar` to use for which `Button`:

```python
string_a = tk.StringVar(value="one")
string_b = tk.StringVar(value="two")
button_a = ttk.Button(window, command=outer_function(string_a))
button_a.pack()
button_b = ttk.Button(window, command=outer_function(string_b))
button_b.pack()

```

When we click each button, it shows the message from the corresponding entry.

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [May 18, 2024, 12:10am UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/4 "2024-05-18T00:10:46Z")

</div>

> Do I understand well that `def` function parameters allow the  
> communication of values between the _function scope_ and the rest of  
> the code?

Yes. In particular, you write the code for the function to work with  
some fixed variable name, eg `name`, and the parameters assign a value  
to `name` for a particular call:

```
 def greeting(name):
     print("Hello", name)

 my_name = "Cameron"
 your_name = "Jan"

 greeting(my_name)
 greeting(your_name)

```

In this way the function does not need to know _anything_ about the code  
which called it or what variable names that code might be using.

> ```python
> def greeting(name):
> print(f"Hi, my name is {name}.")
> 
> greeting("Peter")
> 
> ```
> 
> `{name}` within the `print()` cannot retrieve value outside that function scope so I do have to set greeting parameter?

Well…

Broadly, we do not access variables from outside the function directly.  
We _try_ to write “pure functions” which receive values _only_ through  
their parameters and produce results _only_ by the `return` statement.  
These functions do not have side effects, so they are easy to reason  
able and use safely and correctly.

However, a function has access to its outer scopes. When you use a  
variable name such as `name` in your `greeting()` function Python looks  
for the variable in the local scope i.e. the function’s local variables,  
which include the parameters, and then in outer scopes. Typically that  
outer scope is the module namespace, which is where what you think of as  
“global variables” live.

Example:

```
 DEFAULT_VALUE = 10

 def foo(p=None):
     if p is None:
         p = DEFAULT_VALUE
     print("foo:", p)

```

Here we have a function `foo()` with a parameter `p`. If you don’t  
supply the parameter is defaults to `None` and the function recognises  
that and sets `p=DEFAULT_VALUE` in that case. This kind of this is quite  
common. So: `foo(3)` would print `foo: 3` and `foo()` would print `foo: 10`.

Let’s look at the variables. When you access a variable Python looks for  
its name in the local variables and then in the outer scopes (which are  
just the module.global scope here). For `p` it finds it in the local  
variables because it is a parameter. For `DEFAULT_VALUE` it does not  
find it in the local variables but does find it in the outer scope.

You’ll have noticed that we don’t “declare” variables in Python. When  
you define a function Python scans the code for assignment statements.  
If you assign to the name _anywhere in a function_, that name is a local  
variable. The parameters are assigned to. So Python knows `p` is local  
because it’s a parameter. `DEFAULT_VALUE` is not assigned to, so it must  
be found elsewhere. Note that the assignment does not need to actually  
be run:

```
 def func2():
     print(x)
     x = 2

```

The variable `x` is a local variable because there’s an assignment  
statement in the function code. When you run the above you’ll get a  
`UnboundLocalError` because `x` has not yet been set, but Python still  
knows that it is a local variable, even if the outer scope also had an  
`x` variable.

> And why do the function parameter placeholder sometimes differ from  
> variables in or outside the scope? For example, I define:
> 
> ```python
> def outer_function(whatever):
> def inner_function():
> print("Button pressed.")
> print(input_string.get())
> return inner_function
> 
> ...
> 
> input_string = tk.StringVar(value = "test")
> entry = ttk.Entry(window, textvariable = input_string)
> entry.pack()
> 
> ...
> button = ttk.Button(window, text = "Button 1", command = outer_function(input_string))
> button.pack()
> 
> ```
> 
> The first run of the `outer_function` does not need to retrieve any values from outside the function scope, and on the second run, just the `inner_function` is performed. So why is there a whatever parameter? Do we somehow use `whatever`?

This is more complex than you might think. And, I think, more complex  
than it needs to be.

To answer your question: you’re not using the `whatever` variable. I  
don’t think you need it at all. _As written above_. But I think the code  
above isn’t what might ordinarily be done.

I was thinking that Nice Zombies had missed the point, but now I think  
they’re spot on.

Do I gather you’ve adapted this code from some example?

Let’s examine this code in detail. Starting at the bottom, of course 🙂  
Because the bottom code is the objective. Then we work back to how it is  
done.

So, you’re defining a button:

```
 button = ttk.Button(window, text = "Button 1", command = outer_function(input_string))

```

Here we make a button with the label `Button 1` and arrange that when it  
is pushed it calls a function - that function is passed as the `command`  
parameter to the button setup. The idea is that pressing the button  
prints the current value of the input string, so the function you pass  
must access the object holding the input string.

Now, you’ve also defined an `Entry` widget which stores its stae, the  
input string, in a `StringVar` object which we refer to with the  
`input_string` variable:

```
 input_string = tk.StringVar(value = "test")
 entry = ttk.Entry(window, textvariable = input_string)

```

So your button wants a callback function (the `command` parameter) which  
accesses the `StringVar` to get the current input string value. And that  
is when you call `outer_function()`: `outer_function` is a function  
_which returns a function_. The function it returns is what accesses and  
prints the value. Let’s look at how it is defined:

```
 def outer_function(whatever):
   def inner_function():
     print("Button pressed.")
     print(input_string.get())
   return inner_function

```

What does it do? It defines `inner_function()`, which runs a couple of  
`print()` calls. The second `print` directly accesses `input_string` to  
obtain the value - that’s the `StringVar` object. The `whatever`  
parameter is not used.

This works, but only because you’ve got exactly one `Entry` widget, so  
you get to name it directly in the function. What if you had more, for  
example two entries and two buttons:

```
 input_string = tk.StringVar(value = "test 1")
 entry1 = ttk.Entry(window, textvariable = input_string)
 button = ttk.Button(window, text = "Button 1", command = outer_function(input_string))

 input_string2 = tk.StringVar(value = "test 2")
 entry2 = ttk.Entry(window, textvariable = input_string2)
 button = ttk.Button(window, text = "Button 2", command = outer_function(input_string2))

```

As written, the call to `outer_function(input_string)` or `outer_function(input_string2)`  
ignores the parameter (`whatever`) and returns a function which always  
accesses `input_string`, the first one. Not so good: both buttons report  
on the same `StringVar` object.

I’d be naming these functions differently:

```
 def get_report_on_var(whatever):
   def report():
     print("Button pressed.")
     print(input_string.get())
   return report

```

so that it is more clear that you have a function `report()` which  
reports on the value of some `StringVar`, and a function  
`get_report_on_var()` which returns a report function. So we would set  
up the buttons like this:

```
 button = ttk.Button(window, text = "Button 1", command = get_report_on_var(input_string))
 button = ttk.Button(window, text = "Button 2", command = get_report_on_var(input_string2))

```

But the `report()` function still reaches for the hardwired  
`input_string` object. The _intent_ of the button setups above is more  
clear: we want to report on `input_string` from button 1 and report on  
`input_string2` from button 2. But the `get_report_on_var()` function  
ignores its argument!

What we now want is for `get_report_on_var()` to return a function which  
reports on whatever `StringVar` we hand it. So it needs a further change:

```
 def get_report_on_var(some_var):
   def report():
     print("Button pressed.")
     print(some_var.get())
   return report

```

Now it reports on the particular `StringVar` object you passed in when  
you set up the button, and the parameter (formerly `whatever`) _is not ignored_!

So: how does this work?

What you have above is called a “closure”, where the inner function  
`report()` has access to the variables in its immediate outer scope:  
those local variables of `get_report_on_var()`. When it accesses  
`some_var`, that is not a local variable of `report()`. So Python looks  
in the next outer scope, which is the local variables of  
`get_report_on_var()` _at the time you called it_. That’s important.

When you set up the buttons, you call `get_report_on_var()` to obtain  
the callback function for the button. The `get_report_on_var()` function  
defines a new function called `report()`:

```
 def report():
   print("Button pressed.")
   print(some_var.get())

```

Functions are just another type of object in Python, so this is a kind  
of assignment statement: the name `report` is bound to the function as a  
_local variable_ in `get_report_on_var()`. And the new function you just  
made has access to `get_report_on_var()` local variables, particularly  
`some_var`, which is a local variable because it came from the  
parameters.

When you run a function, the local variables are _new_, unrelated to the  
ones some any earlier or later call: you get a fresh set every time.

So when you define the first button, you call `get_report_on_var()`  
once, and it returns a function which accesses `some_var`, which on that  
call is `input_string`.

When you define the second button, you call `get_report_on_var()` once  
again, and it returns _another_ function which accesses `some_var`,  
which on that call is `input_string2`, the _other_ `StringVar` object`.

These “callback unctions” are not run until you press one of the  
buttons.

I think someone’s trying to teach your about closures, which is why the  
functions had the names `outer_function` and `inner_function`, but  
they’re poorly named for the programme as a whole.

Finally, returning your first question about scopes: the inner function  
`report()` (which gets defines anew on _every_ call to `get_report_on_var()`)  
has 3 scopes to access names:

- its local variables
- the local variables of `get_report_on_var()`
- the module/global variables

---

<div class="post-metadata">

**Author:** ![chepner](https://avatars.discourse-cdn.com/v4/letter/c/22d042/32.png) [@chepner](https://discuss.python.org/u/chepner)\
**Post date:** [May 18, 2024, 7:06pm UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/5 "2024-05-18T19:06:53Z")

</div>

A function parameter is a local variable, but one that can be _defined_ in a special way. For example,

```
def foo(x):
    y = 5
    return x + y

```

Both `x` and `y` are local variables, defined in the scope of `foo`. But while `y` is defined _explicitly_ by an assignment statement, `x` is defined _implicitly_ via a function call. That is,

```
foo(3)

```

basically performs an assignment `x = 3` before entering the body of the function.

---

<div class="post-metadata">

**Author:** ![Juandev](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/juandev/32/14555_2.png) [@Juandev](https://discuss.python.org/u/Juandev)\
**Post date:** [May 20, 2024, 6:13am UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/6 "2024-05-20T06:13:52Z")

</div>

> [@Juandev](#):
>
> ```python
> def outer_function(whatever):
> def inner_function():
> print("Button pressed.")
> print(input_string.get())
> return inner_function
> 
> ```

Yes, I made a mistake when retyping this segment from the video tutorial; the variable name of the second print should be `whatever`, so `print(whatever.get())`.

---

<div class="post-metadata">

**Author:** ![Nineteendo](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/nineteendo/32/19122_2.png) [@Nineteendo](https://discuss.python.org/u/Nineteendo)\
**Post date:** [May 20, 2024, 7:14am UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/7 "2024-05-20T07:14:59Z")

</div>

I recommend to put the main code in a function, that doesn’t hide these errors.

---

<div class="post-metadata">

**Author:** ![Juandev](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/juandev/32/14555_2.png) [@Juandev](https://discuss.python.org/u/Juandev)\
**Post date:** [May 20, 2024, 9:06am UTC](https://discuss.python.org/t/function-parameters-and-naming/53604/8 "2024-05-20T09:06:18Z")

</div>

So, as I understand it now, the `outer_function` parameter placeholder can differ if I am sending into the function just one value because it is clear that the function could receive just one parameter, and there is no uncertainty about which one which could be a case of more complex functions with more parameters.

So for example:

```python
def caller(name):
    print(f"Hello {name}.")

dog = Murphy
caller(dog)

```

Would result in _Hello Murphy_. since I am sending just one parameter to the named function.
