swcarpentry / python-novice-gapminder

Plotting and Programming in Python
http://swcarpentry.github.io/python-novice-gapminder/
Other
163 stars 428 forks source link

"print" in functions causes confusion #588

Open martinosorb opened 2 years ago

martinosorb commented 2 years ago

Learners that have just learned about why a function is useful will not have clearly in mind how functions are usually used in the places they are called. The first reaction I get when they see the first example of function in the lesson, which is def print_greeting(): print('Hello!') is "why don't we just write print?".

A function is best explained as a self-contained piece of code that has inputs and an output. Putting print statements in the function is kind of unusual in well-maintained functions belonging to a library, and causes a lot of confusion, because I then have to explain that there's a big difference between printing the result of an operation and returning it for printing later.

This is even more confusing when we use the Jupyter notebook, because Jupyter automatically prints the output of the last statement in a cell, so also prints a returned value. I then find myself having to explain over and over the following:

The whole thing is very time consuming and confusing.

Therefore I propose the following: the functions episode should be rewritten to avoid functions that contain calls to print, at least at the beginning. A more appropriate example is something like def square(x): return x*x. In this way the idea of what a function is useful for is more clear.

Only at the end, we show that it's possible to build functions that don't return anything, and/or functions that contain calls to print (but to be honest I wouldn't even do that at all).

fercer commented 2 years ago

I think that the first example is introducing what a function is without having to explain the concept of arguments. Also, this shows that a function does not require any argument at all when defined.

As you mentioned, the example of having a function with a single print can be confusing. Maybe having a more lines in that function can express the idea in a better way, Something like

def print_greetin():
    print('Hello!')
    print('The weather is nice today.')
    print('Right?')
sstevens2 commented 1 year ago

FYI, I'm going to make a PR adding @fercer's recommendation next week as apart of a demo on how to edit lessons in GitHub for CarpentryCon next week.

rashid-bioinfo commented 1 year ago

If you want to avoid print statement in a function definition, then save the value in a variable and return that variable, on calling that variable will print whatever stored in that variable. For example:

def somefunc(): ... x = 'That was a waste of my time' ... return x ... somefunc() 'That was a waste of my time'

brownsarahm commented 1 year ago

I understand the goal to introduce a function without arguments. I am curious, however, about the risk of creating an initial mental model that learners will struggle to update and that promotes bad habits (side effects instead of returns) of the type that make code harder to debug and use later. There are some "bad habits" that only impact performance nominally in a modern computer, but this one is the type that I see my computer science students in my regular job outside of the Carpentries struggle with the effects of. For example tests not passing when their "function does the right thing" because they use print instead of return.

What learners see first is going to get extra weight and be considered the default, whether that was the goal when it was written that way or not.

I propose something like

def make_greeting(name):
    return "Hello " + name

At this point in the lesson, the learners have already seen lots of arguments when using builtin functions and libraries, so this is more showing them behind the scenes of what they already know than introducing too many things at once. They have also already seen docstrings in help, so they know that function calls can look approximately like this.

I think at this point in the lesson a mental model that will serve them is more important than the minimal code that will run.

Starting with what is best practice, even if a bit more complex, still fits within Carpentries pedagogy.

martinosorb commented 1 year ago

I agree, Sarah, and that's the idea behind my initial post. For me the basic mental model of a function should be a machine that turns inputs into outputs -- many people will also already have the mathematical definition in mind, of y = f(x). I like what you propose.

brownsarahm commented 1 year ago

I avoided a math one for the case of math being distracting and anxiety inducing, but yes I was attempting to agree with you while changing the themes in the lesson as little as possible

gyengen commented 1 year ago

Students don't tend to understand what is the point using a function. Using examples like a function without proper input or output (even worse using print functions inside) will usually just make things worse. I think the biggest issue is that we are using too simple source codes as examples where functions are indeed unnecessary.

Therefore these simple examples fail to demonstrate really useful features of functions like:

@martinosorb I would avoid using math examples when teaching functions. It could just make some people anxious who thinks they will not understand it because of some lack of knowledge in maths.