学习用 Thonny 写代码： 一个面向初学者的Python IDE
Thonny Python
![](/data/attachment/album/201806/27/093343c6gzva2ha9mg2ocd.jpg)


学习编程很难。即使当你最终怎么正确使用你的冒号和括号，但仍然有很大的可能你的程序不会如果所想的工作。 通常，这意味着你忽略了某些东西或者误解了语言结构，你需要在代码中找到你的期望与现实存在分歧的地方。


程序员通常使用被叫做<ruby> 调试器 <rt>  debugger </rt></ruby>的工具来处理这种情况，它允许一步一步地运行他们的程序。不幸的是，大多数调试器都针对专业用途进行了优化，并假设用户已经很好地了解了语言结构的语义（例如：函数调用）。


Thonny 是一个适合初学者的 Python IDE，由爱沙尼亚的 [Tartu 大学](https://www.ut.ee/en) 开发，它采用了不同的方法，因为它的调试器是专为学习和教学编程而设计的。


虽然 Thonny 适用于像小白一样的初学者，但这篇文章面向那些至少具有 Python 或其他命令式语言经验的读者。


### 开始


从第 Fedora 27 开始，Thonny 就被包含在 Fedora 软件库中。 使用 `sudo dnf install thonny` 或者你选择的图形工具（比如“<ruby> 软件 <rt>  Software </rt></ruby>”）安装它。


当第一次启动 Thonny 时，它会做一些准备工作，然后呈现一个空白的编辑器和 Python shell 。将下列程序文本复制到编辑器中，并将其保存到文件中（`Ctrl+S`）。



```
n = 1
while n < 5:
    print(n * "*")
    n = n + 1

```

我们首先运行该程序。 为此请按键盘上的 `F5` 键。 你应该看到一个由星号组成的三角形出现在 shell 窗格中。


![一个简单的 Thonny 程序](/data/attachment/album/201806/27/093345ppd7wp8ww8m5k88g.png)


Python 分析了你的代码并理解了你想打印一个三角形了吗？让我们看看！


首先从“<ruby> 查看 <rt>  View </rt></ruby>”菜单中选择“<ruby> 变量 <rt>  Variables </rt></ruby>”。这将打开一张表格，向我们展示 Python 是如何管理程序的变量的。现在通过按 `Ctrl + F5`（在 XFCE 中是 `Ctrl + Shift + F5`）以调试模式运行程序。在这种模式下，Thonny 使 Python 在每一步所需的步骤之前暂停。你应该看到程序的第一行被一个框包围。我们将这称为焦点，它表明 Python 将接下来要执行的部分代码。


![ Thonny 调试器焦点 ](/data/attachment/album/201806/27/093346jplvlpbpac2k25il.png)


你在焦点框中看到的一段代码段被称为赋值语句。 对于这种声明，Python 应该计算右边的表达式，并将值存储在左边显示的名称下。按 `F7` 进行下一步。你将看到 Python 将重点放在语句的正确部分。在这个例子中，表达式实际上很简单，但是为了通用性，Thonny 提供了表达式计算框，它允许将表达式转换为值。再次按 `F7` 将文字 `1` 转换为值 `1`。现在 Python 已经准备好执行实际的赋值—再次按 `F7`，你应该会看到变量 `n` 的值为 `1` 的变量出现在变量表中。


![Thonny 变量表](/data/attachment/album/201806/27/093347eauc8l683lmz8aml.png)


继续按 `F7` 并观察 Python 如何以非常小的步骤前进。它看起来像是理解你的代码的目的或者更像是一个愚蠢的遵循简单规则的机器？


### 函数调用


<ruby> 函数调用 <rt>  Function Call </rt></ruby>是一种编程概念，它常常给初学者带来很大的困惑。从表面上看，没有什么复杂的事情——给代码命名，然后在代码中的其他地方引用它（调用它）。传统的调试器告诉我们，当你进入调用时，焦点跳转到函数定义中（然后稍后神奇地返回到原来的位置）。这是整件事吗？这需要我们关心吗？


结果证明，“跳转模型” 只对最简单的函数是足够的。理解参数传递、局部变量、返回和递归都得理解堆栈框架的概念。幸运的是，Thonny 可以直观地解释这个概念，而无需在厚厚的掩盖下搜索重要的细节。


将以下递归程序复制到 Thonny 并以调试模式（`Ctrl+F5` 或 `Ctrl+Shift+F5`）运行。



```
def factorial(n):
    if n == 0:
        return 1
    else:
        return factorial(n-1) * n

print(factorial(4))

```

重复按 `F7`，直到你在对话框中看到表达式 `factorial(4)`。 当你进行下一步时，你会看到 Thonny 打开一个包含了函数代码、另一个变量表和另一个焦点框的新窗口（移动窗口以查看旧的焦点框仍然存在）。


![通过递归函数的 Thonny](/data/attachment/album/201806/27/093351g0ot4bt0vt749em9.png)


此窗口表示堆栈帧，即用于解析函数调用的工作区。几个放在彼此顶部的这样的窗口称为<ruby> 调用堆栈 <rt>  call stack </rt></ruby>。注意调用位置的参数 `4` 与 “局部变量” 表中的输入 `n` 之间的关系。继续按 `F7` 步进, 观察在每次调用时如何创建新窗口并在函数代码完成时被销毁，以及如何用返回值替换了调用位置。


### 值与参考


现在，让我们在 Python shell 中进行一个实验。首先输入下面屏幕截图中显示的语句：


![Thonny shell 显示列表突变](/data/attachment/album/201806/27/093353zpfwowfs6pkxk4kl.png)


正如你所看到的, 我们追加到列表 `b`, 但列表 `a` 也得到了更新。你可能知道为什么会发生这种情况, 但是对初学者来说，什么才是最好的解释呢？


当教我的学生列表时，我告诉他们我一直欺骗了他们关于 Python 内存模型。实际上，它并不像变量表所显示的那样简单。我告诉他们重新启动解释器（工具栏上的红色按钮），从“<ruby> 查看 <rt>  View </rt></ruby>”菜单中选择“<ruby> 堆 <rt>  Heap </rt></ruby>”，然后再次进行相同的实验。如果这样做，你就会发现变量表不再包含值——它们实际上位于另一个名为“<ruby> 堆 <rt>  Heap </rt></ruby>”的表中。变量表的作用实际上是将变量名映射到地址（或称 ID），地址又指向了<ruby> 堆 <rt>  Heap </rt></ruby>表中的行。由于赋值仅更改变量表，因此语句 `b = a` 只复制对列表的引用，而不是列表本身。这解释了为什么我们通过这两个变量看到了变化。


![在堆模式中的 Thonny](/data/attachment/album/201806/27/093355rx3qtquluvtu3vsq.png)


（为什么我要在教列表的主题之前推迟说出内存模型的事实？Python 存储的列表是否有所不同？请继续使用 Thonny 的堆模式来找出结果！在评论中告诉我你认为怎么样！）


如果要更深入地了解参考系统, 请将以下程序通过打开堆表复制到 Thonny 并进行小步调试（`F7`） 中。



```
def do_something(lst, x):
    lst.append(x)

a = [1,2,3]
n = 4
do_something(a, n)
print(a)

```

即使“堆模式”向我们显示真实的图片，但它使用起来也相当不方便。 因此，我建议你现在切换回普通模式（取消选择“<ruby> 查看 <rt>  View </rt></ruby>”菜单中的“<ruby> 堆 <rt>  Heap </rt></ruby>”），但请记住，真实模型包含变量、参考和值。


### 结语


我在这篇文章中提及到的特性是创建 Thonny 的主要原因。很容易对函数调用和引用形成错误的理解，但传统的调试器并不能真正帮助减少混淆。


除了这些显著的特性，Thonny 还提供了其他几个初学者友好的工具。 请查看 [Thonny的主页](http://thonny.org) 以了解更多信息！




---


via: <https://fedoramagazine.org/learn-code-thonny-python-ide-beginners/>


作者：[Aivar Annamaa](https://fedoramagazine.org/) 译者：[Auk7F7](https://github.com/Auk7F7) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
Learning to program is hard. Even when you finally get your colons and parentheses right, there is still a big chance that the program doesn’t do what you intended. Commonly, this means you overlooked something or misunderstood a language construct, and you need to locate the place in the code where your expectations and reality diverge.

Programmers usually tackle this situation with a tool called a *debugger*, which allows running their program step-by-step. Unfortunately, most debuggers are optimized for professional usage and assume the user already knows the semantics of language constructs (e.g. function call) very well.

Thonny is a beginner-friendly Python IDE, developed in [University of Tartu](https://www.ut.ee/en), Estonia, which takes a different approach as its debugger is designed specifically for learning and teaching programming.


Although Thonny is suitable for even total beginners, this post is meant for readers who have at least some experience with Python or another imperative language.

# Getting started

Thonny is included in Fedora repositories since version 27. Install it with *sudo dnf install thonny* or with a graphical tool of your choice (such as *Software*).

When first launching Thonny, it does some preparations and then presents an empty editor and the Python shell. Copy following program text into the editor and save it into a file (Ctrl+S).

n = 1 while n < 5: print(n * "*") n = n + 1

Let’s first run the program in one go. For this press *F5* on the keyboard. You should see a triangle made of periods appear in the shell pane.

![A simple program in Thonny](https://fedoramagazine.org/wp-content/uploads/2017/12/scr1.png)

A simple program in Thonny

Did Python just analyze your code and understand that you wanted to print a triangle? Let’s find out!

Start by selecting “Variables” from the “View” menu. This opens a table which will show us how Python manages program’s variables. Now run the program in *debug mode* by pressing *Ctrl+F5* (or *Ctrl+Shift+F5* in XFCE). In this mode Thonny makes Python pause before each step it takes. You should see the first line of the program getting surrounded with a box. We’ll call this *the focus* and it indicates the part of the code Python is going to execute next.

![Thonny debugger focus](https://fedoramagazine.org/wp-content/uploads/2017/12/thonny-scr2.png)

Thonny debugger focus

The piece of code you see in the focus box is called assignment statement. For this kind of statement, Python is supposed to evaluate the expression on the right and store the value under the name shown on the left. Press *F7* to take the next step. You will see that Python focused on the right part of the statement. In this case the expression is really simple, but for generality Thonny presents the expression evaluation box, which allows turning expressions into values. Press *F7* again to turn the *literal* 1 into *value* 1. Now Python is ready to do the actual assignment — press *F7* again and you should see the variable *n* with value 1 appear in the variables table.

![Thonny with variables table](https://fedoramagazine.org/wp-content/uploads/2017/12/thonny-scr3.png)

Thonny with variables table

Continue pressing F7 and observe how Python moves forward with really small steps. Does it look like something which understands the purpose of your code or more like a dumb machine following simple rules?

# Function calls

Function call is a programming concept which often causes great deal of confusion to beginners. On the surface there is nothing complicated — you give name to a code and refer to it (call it) somewhere else in the code. Traditional debuggers show us that when you step into the call, the focus jumps into the function definition (and later magically back to the original location). Is it the whole story? Do we need to care?

Turns out the “jump model” is sufficient only with the simplest functions. Understanding parameter passing, local variables, returning and recursion all benefit from the notion of *stack frame*. Luckily, Thonny can explain this concept intuitively without sweeping important details under the carpet.

Copy following recursive program into Thonny and run it in debug mode (*Ctrl+F5* or *Ctrl+Shift+F5*).

deffactorial(n):ifn == 0: return 1else: return factorial(n-1) * n print(factorial(4))

Press *F7* repeatedly until you see the expression *factorial(4)* in the focus box. When you take the next step, you see that Thonny opens a new window containing function code, another variables table and another focus box (move the window to see that the old focus box is still there).

![Thonny stepping through a recursive function](https://fedoramagazine.org/wp-content/uploads/2017/12/thonny-scr4.png)

Thonny stepping through a recursive function

This window represents a stack frame, the working area for resolving a function call. Several such windows on top of each other is called *the call stack*. Notice the relationship between argument *4* on the call site and entry *n* in the local variables table. Continue stepping with *F7* and observe how new windows get created on each call and destroyed when the function code completes and how the call site gets replaced by the return value.

# Values vs. references

Now let’s make an experiment inside the Python shell. Start by typing in the statements shown in the screenshot below:

![Thonny shell showing list mutation](https://fedoramagazine.org/wp-content/uploads/2017/12/thonny-scr5.png)

Thonny shell showing list mutation

As you see, we appended to list *b*, but list *a* also got updated. You may know why this happened, but what’s the best way to explain it to a beginner?

When teaching lists to my students I tell them that I have been lying about Python memory model. It is actually not as simple as the variables table suggests. I tell them to restart the interpreter (the red button on the toolbar), select “Heap” from the “View” menu and make the same experiment again. If you do this, then you see that variables table doesn’t contain the values anymore — they actually live in another table called “Heap”. The role of the variables table is actually to map the variable names to addresses (or ID-s) which refer to the rows in the heap table. As assignment changes only the variables table, the statement *b = a* only copied the reference to the list, not the list itself. This explained why we see the change via both variables.

![Thonny in heap mode](https://fedoramagazine.org/wp-content/uploads/2017/12/thonny-scr6.png)

Thonny in heap mode

(Why do I postpone telling the truth about the memory model until the topic of lists? Does Python store lists differently compared to floats or strings? Go ahead and use Thonny’s heap mode to find this out! Tell me in the comments what do you think!)

If you want to understand the references system deeper, copy following program to Thonny and small-step (*F7*) through it with the heap table open.

defdo_something(lst, x): lst.append(x) a = [1,2,3] n = 4 do_something(a, n) print(a)

Even if the “heap mode” shows us authentic picture, it is rather inconvenient to use. For this reason, I recommend you now switch back to normal mode (unselect “Heap” in the View menu) but remember that the real model includes variables, references and values.

# Conclusion

The features I touched in this post were the main reason for creating Thonny. It’s easy to form misconceptions about both function calls and references but traditional debuggers don’t really help in reducing the confusion.

Besides these distinguishing features, Thonny offers several other beginner friendly tools. Please look around at [Thonny’s homepage](http://thonny.org) to learn more!

## Dane

I’m no python expert, but when I started playing around with it Thonny made it a lot easier. Seems to be one of the IDE’s most people recommend when learning the language.

## Nice

Ruby is more clear and nice

n = 1

while n<5

puts “*” * n

n += 1

end

or better

5.times {|t| puts “*” * t}

## Nick

@nice

You should do a bit more reading on python before you make such calls.

Ruby is not clearer or nicer.

Here is that same loop in python:

for i in range(1,5):

print(“*” * i)

Also, the last example is very unclear.

Being able to write something shorter, or on one line, is not always an advantage.

I will admit that it’s probably because I find that to be a strange notation of lambda expressions.

## Rene Reichenbach

It is usually not helpful to respond with “use another language” to an article that describes use of an IDE. It obviously assumes that someone already decided for Python to learn.

Article and tool are nice i think.

If you do not like Python as I do not really like it you still should not just “offend” others. Its important to not be toxic in the community.

## Cornel Panceac

Easy intro to debugging, stack frames, heap and python. Thank you!

## gokhan s.

thonny install step;

fedora 21-to 26 > bash <(curl -s http://thonny.org/installer-for-linux)

fedora 27> dnf install thonny

thats all 🙂

## Dani Konoplya

Great idea! I think it will very help for people are learn algorithms and different coding interview questions are using recursion. Frequently we have hear not think too much about how is recursion working because it is too complex . However with your tool it is possible to understand exactly what is going inside. This is even change variable to their value , amazing, you even don’t need to use watches . Everything is straight in front of your eyes.

## Yushi

Great idea! I think it will very help for people are learn algorithms and different coding interview questions are using recursion. Frequently we have hear not think too much about how is recursion working because it is too complex . However with your tool it is possible to understand exactly what is going inside. This is even change variable to their value , amazing, you even don’t need to use watches . Everything is straight in front of your eyes.