「いちばんやさしいPython入門教室」修正



# テキスト修正

「いちばんやさしいPython入門教室」<sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup>で演習をすすめてきました．このテキストはひとつひとつのcodeがどのような考え方でそこにあるのかを丁寧に解説してくれています．なので，coding初心者がcodingを理解するために，じっくり読むのにはとてもいいテキストです．ただ，論理の流れを重視しているためか，すこしcodingの常識からずれているところがあります．その修正です．


## example07-08-01.pyの修正(tag版)

このあたりのコード，まずいです．

長くやったり，たくさんやったりしたらもたもたしてきます．はじめは，cpuとかのせいかとおもってあきらめてたんですが，あまりに遅くって．．．

修正のアイデアはどっかにあったんですが，もうだいぶむかしに修正しちゃったのでなにが原典だったかわかりません． -[タグとバインド](http://bacspot.dip.jp/virtual_link/www/si.musashi-tech.ac.jp/new_www/Python_IntroTkinter/03/index-5.html)が最初のアイデアとしては同じです．

問題は，

    canvas.create_oval(self.x - 20, self.y - 20,
    self.x + 20, self.y + 20, fill="white", width=0)

です．'white'で上書きして，消しています．これはcodeで絵をかくときの常とう手段です．画面全体をpictとして管理して書いていくときには効率がいいんです．でも，objectに対して，これをやるとobjectがどんどん増殖します．結果として必要なメモリーが増えて，描画がもたもたしてくるんです．たぶん

なんで正しくはobjectをdeleteします．

まず，create\_ovalで識別のためにtagをつけて生成します．

```python
canvas.create_oval(self.x - 20, self.y - 20,
		   self.x + 20, self.y + 20, 
		   fill=self.color, width=0, 
		   tag=self.color)
```

それを=white=で上書きする代わりに，つぎのようにしてdeleteします．

```python
canvas.delete(self.color)
```

これで試してみてください．とっても速くなるはずです．

ただ，windowsでは形がいびつな感じがするかもしれません．これは，描画ライブラリのせいのようです<sup><a id="fnr.2" class="footref" href="#fn.2">2</a></sup>．mac版ではばっちりです．


## さらに正統派(obj版)

さらにobjectを消すという考え方の方がわざわざtagで識別するより筋が良さそうです． -<https://pythonprogramming.altervista.org/delete-an-object-on-the-canvas/?doing_wp_cron=1591052096.4730188846588134765625>

基本的には，

```python
canvas.delete(self.ball)
... 中略 ...
self.ball = canvas.create_oval(self.x - 20, self.y - 20,
		   self.x + 20, self.y + 20, 
		   fill=self.color, width=0)
```

としてself.ballというobjectにしてしまって，それを，deleteするだけです．でも，元テキストからはcodeの順番を相当いじる必要があります．

完成形をつけておきますので，時間のある人は，どこがどうなっているか，なんでか悩んで見てください．順番は，

1.  上のように修正してみる 2.

self.ballがないと怒られるので，initでnoneしておく 3.canvasがないと怒られるので，ballsを生成する前に持っていく です．

```python
import tkinter as tk
speed = 10
class Ball:
  global speed
  def __init__(self, x, y, dx, dy, color):
    self.x = x
    self.y = y
    self.dx = dx
    self.dy = dy
    self.color = color
    self.ball = None

  def test(self):
    print(self.x)
    print(self.y)
  def move(self, canvas):
    canvas.delete(self.ball)
    self.x = self.x + self.dx
    self.y = self.y + self.dy
    self.ball = canvas.create_oval(self.x - 20, self.y - 20,
		       self.x + 20, self.y + 20, 
		       fill=self.color, width=0)
    if self.x >= canvas.winfo_width():
      self.dx = -speed
    if self.x < 0:
      self.dx = +speed
    if self.y >= canvas.winfo_height():
      self.dy = -speed
    if self.y < 0:
      self.dy = +speed

root = tk.Tk()
root.geometry("600x400")

canvas = tk.Canvas(root, width=600, height=400, bg="white")
canvas.place(x=0, y=0)

balls = [
  Ball(300, 400, 1, 1, "red"),
  Ball(200, 400, 2, 1, "green"),
  Ball(300, 200, 1, 2, "blue")
]
def loop():
  for b in balls:
    b.move(canvas)
  root.after(10, loop)


root.after(10, loop)
root.mainloop()
```


# Footnotes

<sup><a id="fn.1" href="#fnr.1">1</a></sup> 「いちばんやさしいPython入門教室」大澤文孝著,(ソーテック社出版,2017).

<sup><a id="fn.2" href="#fnr.2">2</a></sup> (2020/06/16追記)バックを黒くして，ボールを明るくするとうまく出ます．人間の目のせいでしょうか．．


------
 - **source** ~/Desktop/lecture_21s/CompAInfo/tmp.org