Skip to content

gh-107017: Rework the Fibonacci example #107132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 113 additions & 63 deletions Doc/tutorial/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ Lists
Python knows a number of *compound* data types, used to group together other
values. The most versatile is the *list*, which can be written as a list of
comma-separated values (items) between square brackets. Lists might contain
items of different types, but usually the items all have the same type. ::
items of different types, but usually the items all have the same type::

>>> squares = [1, 4, 9, 16, 25]
>>> squares
Expand Down Expand Up @@ -478,73 +478,123 @@ example::
First Steps Towards Programming
===============================

Of course, we can use Python for more complicated tasks than adding two and two
together. For instance, we can write an initial sub-sequence of the
`Fibonacci series <https://en.wikipedia.org/wiki/Fibonacci_number>`_
as follows::

>>> # Fibonacci series:
... # the sum of two elements defines the next
... a, b = 0, 1
>>> while a < 10:
... print(a)
... a, b = b, a+b
...
0
We can use Python for more complex tasks than adding two and two together.
For instance, we can compute the numbers of the
`Fibonacci series <https://en.wikipedia.org/wiki/Fibonacci_number>`_.
To do that we need to utilize three following concepts.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
To do that we need to utilize three following concepts.
To do that we need to use the three following concepts.

Let's use the plain English "use" instead of "utilize".


Multiple Assignment
-------------------

A *multiple assignment* of variables us allows to set values of more than one
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A *multiple assignment* of variables us allows to set values of more than one
A *multiple assignment* of variables us allows to set the values of more than one

variable on a single line. Notice that if the value assignment is a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
variable on a single line. Notice that if the value assignment is a
variable on a single line. Notice that if the value assignment is an

expression, it is first evaluated and then assigned::

>>> a, b = 1, 5 # multiple assignment of two variables
>>> a
1
>>> b
5
>>> a, b = b, a + b # first a is set to value of b, then b is set to sum of a and b
>>> a
5
>>> b
6

Repeating our code
------------------

The :keyword:`while` loop is example of a repeating cycle. It performs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The :keyword:`while` loop is example of a repeating cycle. It performs
The :keyword:`while` loop is an example of a repeating cycle. It performs

a block of code continuously as long as the condition is
fulfilled. The test used in the example is a simple comparison you might
know from arithmetics. Fulfilled conditions have the value ``True``.
Unfulfilled conditions have the value ``False``::

>>> 1 < 3 # 1 is less than 3
True
>>> 'king' == "king" # the strings are equal
True
>>> 4 >= 6 # 4 is not greater than or equal to 6
False

In Python, the following comparison operators are used:

* ``<``: Less than
* ``>``: Greater than
* ``==``: Equal to
* ``<=``: Less than or equal to
* ``>=``: Greater than or equal to
* ``!=``: Not equal to

Let's create a simple loop. We need the keyword ``while`` and a condition;
in this case, ``count < 5``. To ensure that the loop finishes, we must make
sure that the condition is *not fulfilled* at a certain step. Otherwise, the
code would repeat indefinitely. To achieve that, we can increase the value
of count. As soon as the variable ``count`` reaches the value 5, the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
of count. As soon as the variable ``count`` reaches the value 5, the
of ``count``. As soon as the variable ``count`` reaches the value 5, the

condition will be ``False``::

>>> count = 0; # define variable to which we will be adding 1 in a loop
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
>>> count = 0; # define variable to which we will be adding 1 in a loop
>>> count = 0 # define variable to which we will be adding 1 in a loop

>>> while count < 5: count = count + 1 # hit enter one more time to start the loop
...
>>> count # when count reached value of 5, while loop finished
5

Note that block inside the ``while`` loop, or *body* of the loop is *indented*.
Comment on lines +537 to +542
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example above uses a one-liner: while count < 5: count = count + 1

Let's use indentation in the example, to match the text. Something like this?

Suggested change
>>> while count < 5: count = count + 1 # hit enter one more time to start the loop
...
>>> count # when count reached value of 5, while loop finished
5
Note that block inside the ``while`` loop, or *body* of the loop is *indented*.
>>> while count < 5:
... count = count + 1 # hit enter one more time to start the loop
...
>>> count # when count reached value of 5, while loop finished
5
Note that block inside the ``while`` loop, or *body* of the loop is *indented*.

Indentation is Python's way of grouping statements together. When you use
the Python shell, you need to type a tab or space(s) for each indented line.
Each line within a block must be indented by the same amount.
When we want to exit the indented block of code in the Python shell, we must
follow it by a blank line to indicate its completion. This way, the parser
knows we have finished typing the last line)::

>>> number = 1
>>> while number < 5:
... print(number)
... number = number + 1 # increase the value by one with each repetition
...
1
2
3
5
8

This example introduces several new features.

* The first line contains a *multiple assignment*: the variables ``a`` and ``b``
simultaneously get the new values 0 and 1. On the last line this is used again,
demonstrating that the expressions on the right-hand side are all evaluated
first before any of the assignments take place. The right-hand side expressions
are evaluated from the left to the right.

* The :keyword:`while` loop executes as long as the condition (here: ``a < 10``)
remains true. In Python, like in C, any non-zero integer value is true; zero is
false. The condition may also be a string or list value, in fact any sequence;
anything with a non-zero length is true, empty sequences are false. The test
used in the example is a simple comparison. The standard comparison operators
are written the same as in C: ``<`` (less than), ``>`` (greater than), ``==``
(equal to), ``<=`` (less than or equal to), ``>=`` (greater than or equal to)
and ``!=`` (not equal to).

* The *body* of the loop is *indented*: indentation is Python's way of grouping
statements. At the interactive prompt, you have to type a tab or space(s) for
each indented line. In practice you will prepare more complicated input
for Python with a text editor; all decent text editors have an auto-indent
facility. When a compound statement is entered interactively, it must be
followed by a blank line to indicate completion (since the parser cannot
guess when you have typed the last line). Note that each line within a basic
block must be indented by the same amount.

* The :func:`print` function writes the value of the argument(s) it is given.
It differs from just writing the expression you want to write (as we did
earlier in the calculator examples) in the way it handles multiple arguments,
floating point quantities, and strings. Strings are printed without quotes,
and a space is inserted between items, so you can format things nicely, like
this::

>>> i = 256*256
>>> print('The value of i is', i)
The value of i is 65536

The keyword argument *end* can be used to avoid the newline after the output,
or end the output with a different string::

>>> a, b = 0, 1
>>> while a < 1000:
... print(a, end=',')
... a, b = b, a+b
...
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
4

Function arguments
------------------

We already know the :func:`print` function, which writes the value of the
argument(s) it receives on screen. The arguments are enclosed within
parentheses ``()``. In simplest form, like ``print(a, b)``, the arguments
are positional, meaning the function processes them in the same order
Comment on lines +565 to +566
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
parentheses ``()``. In simplest form, like ``print(a, b)``, the arguments
are positional, meaning the function processes them in the same order
parentheses ``()``. In its simplest form, like ``print(a, b)``, the arguments
are positional, meaning the function processes them in the same order

as they are written::

>>> group = "Knights"
>>> say_what = '"Ni!"'
>>> print(group, 'Who Say', say_what)
Knights Who Say "Ni!"

The ``print()`` function also offers a useful keyword argument called *end*,
which can be used to avoid the newline after the output, or end the output
with a different string::

>>> count = 0
>>> count = 10
>>> while count > 5:
... print(count, end=' ') # end the output of print() with a whitespace
... count = count - 1 # decrease the value by one with each repetition
...
10 9 8 7 6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an elegant touch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you :)


Fibonacci series
----------------

Great! Now that we have the knowledge, let's write code to print all numbers
from the Fibonacci series that are lower than 150::

>>> a, b = 0, 1
>>> while a < 150:
... print('', a, '', end='->')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this utilities the print sep param, however this is nor explained nor inferred, so to a beginner it may be confusing

Perhaps it could be beneficial to show off f-strings like

Suggested change
... print('', a, '', end='->')
... print(f'{a} ->', end='')

Or to keep end as ->

Suggested change
... print('', a, '', end='->')
... print(f'{a} ', end="->")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I very strongly prefer the original print('', a, '', end='->'), which reduces the punctuation the learner has to deal with to a minimum, and emphasises instead the connection between more easily assimilated things, like the English word "end" and the "arrow" ("->").

Showing off f-strings while demonstrating a different functionality introduces unnecessary cognitive burden. Two different kinds of quotes and two different kinds of brackets requires a lot of parsing and stopping. I don't think this is the right solution here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning: As this is an Introduction chapter, I wanted to keep the number of introduced concepts to the minimum. There are ways to code this better, but it is not formally wrong. The default separator is already shown in the example above and this just builds on that, so it's hopefully not confusing to the reader.

... a, b = b, a + b
...
0 -> 1 -> 1 -> 2 -> 3 -> 5 -> 8 -> 13 -> 21 -> 34 -> 55 -> 89 -> 144 ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I like the way that the example illustrates the value of using end - no need to explain, the example does it much more effectively. This will stick in someone's mind.


.. rubric:: Footnotes

Expand Down