2018年6月13日水曜日

【Python】簡単な家を描きました【タートルグラフィックス】

この前、私は タートルグラフィックスの本(英語) を買いました( 簡単なレビューはこちら )。

その本を読みながら、「Pythonやタートルグラフィックス」についての基本的な説明をしていこうと思います。 入門的な記事を10個くらい投稿する予定です。なるべく専門用語の英訳も表記します。

今回、その本が出題してる練習問題を解いてみます。 まずはシンプルな家を描くプログラムです。 ちなみに、解答例とはかなり違います。

亀の家を描くプログラム

ソースコード

家を描くプログラムのソースコードはこちらです。googleドライブにも保管しています。 Python をインストールしているなら、ダブルクリックするだけで、プログラムを動かせます。

import turtle

#------------------画面を設定----------------
width = 500 # 横幅
height = 500 # 高さ
scr = turtle.Screen() # 絵を描く画面を作る
scr.title ('House') # 画面の上に house というタイトルを表示
scr.setup (width , height, 0, 0) # 画面の大きさを"width x height"に設定。左上の位置に出現します

#---------------カーソル(亀)の設定-----------------
ttl = turtle.Turtle() # カーソル(亀)のインスタンスを作成
ttl.shape('turtle') # カーソルの形を亀に設定
ttl.screen.screensize(width+100 , height+100) # 画面をスクロールできる範囲
ttl.speed(2) # 絵を描くスピード
ttl.shapesize(1) # カーソル(亀)のサイズ
ttl.pensize(1) # ペンの太さ
ttl.color('brown') # ペンの色

#-------------家の設定---------------
square_length = 300 # 正方形の一辺の長さ
triangle_height = square_length/4 # 三角形の高さ
centerX = 0 # 正方形の中心のx座標
centerY = 0 # 正方形の中心のy座標

#--------------正方形の右上の点に移動-------------------
x = centerX + square_length/2
y = centerY + square_length/2
ttl.penup() # ペンを上げる(移動中に線が引かれないようになる)
ttl.goto(x, y) # 正方形の右上の点に移動

#------------------屋根を描く(右から左へ)---------------
ttl.pendown() # ペンを下げる(移動中に線が引かれるようになる)

# 左上に線を引く
x = centerX
y = centerY + square_length/2 + triangle_height
ttl.goto(x, y) # 屋根の一番上に移動

# 左下に線を引く
x = centerX - square_length/2
y = centerY + square_length/2
ttl.goto(x, y) # 正方形の左上の点に移動

#------------------正方形の部分を描く--------------
ttl.setheading(270) # 下を向く
for i in range(4):
    ttl.forward(square_length) # 前に線を引く
    ttl.left(90) # 左に90度回転

#------------------真ん中に亀のスタンプを押す--------------------
ttl.penup() # ペンを上げる(移動中に線が引かれないようになる)
ttl.goto(centerX, centerY) # 真ん中に戻る
ttl.setheading(90) # 上を向く
ttl.stamp() # 亀のスタンプをつける

# 画面をクリックしたら終了
scr.exitonclick()

プログラムを簡潔に説明します

変数へ代入:「x=0」 は 「xに0を代入する」という意味

変数 と リテラル

「プログラミングの変数」 は 「数学の変数」 とほぼ同じです。 「変数の名前」を適当に決めて、 そこに 整数や文字列などの値 を代入できます。

ただし、「変数の名前の先頭はアルファベットである」という決まりがあります。 x, num, num2, name1 のように、 全ての変数はアルファベットから始まります。

リテラル(literal)とは 下のような定数のことです。

  • 整数: 1, 5000, -100
  • 浮動小数点数: 3.0, 42.195, -10.5
  • 文字列: "brown", 'hello', "200"

リテラルは変数とは対照的です。 変数は代入によって値を保持していますが、 リテラルは文字通りに直接そのまま値が記述されています。

さて、ここで引用符について整理したいと思います。

  • 引用符で囲まれている
    • 文字列 ("brown", 'hello', "200")
  • 引用符で囲まれていない
    • 変数(x, num, num2, name1)
    • 整数(1, 5000, -100
    • 浮動小数点数(3.0, 42.195, -10.5

「引用符を付け忘れた文字列」 は 「未定義の変数」 になってしまいます。 私はうっかりしている時、そのエラーをよく出します。

「変数名の先頭の文字」 が 数字 でいいとしたら、数字なのか変数なのか分かりにくいですね。 だから、「変数名の先頭の文字はアルファベットである」という決まり は 意味ある決まりと言えそうです。

= で 変数に値を代入できる

プログラミングの世界では、x=0 は「変数xに0を代入すること」を意味します。 「xが0に等しい」という意味ではありません。

= は 代入演算子(assignment operator) です。 左の変数(variable) に 右の値 を代入します。

私が真面目に勉強したプログラミング言語は少ないですが、 「Hello world! のプログラム」をいろんな言語で書いた経験から言わせてもらいます。

たぶん、ほとんどのプログラミング言語で = は代入を意味します。 例外はR言語。R言語では <- を用いて変数に値を代入します。

R言語 は 統計に強いプログラミング言語 です。 R言語 は 「少し難しい統計の授業」 でも使われてるでしょう。高校か大学で。

いろんな種類のデータ:整数、文字列など

データの種類

いろんなデータの種類があります。

  • int: 整数(integer)
  • float: 浮動小数点数(floating point number)
  • str: 文字列(string)
  • list: リスト(list)
  • dict: 辞書(dictionary)
  • tuple: タプル、テュポォ(tuple)

まずは、上の3つのデータ型を知っていれば十分な気がします。

あらゆるデータがオブジェクトとして扱われている

Pythonでは、 変数(variable) や リテラル(literal,定数) も オブジェクト(物) として扱われます。 あらゆるデータがオブジェクトとして扱われていると言ってもいいかもしれません。

type()関数を使えば、オブジェクトのクラスを確認することができます。

リテラルもオブジェクト

リテラルもオブジェクトです。

例えば、3 は int class(整数クラス)、 3.0 は float class (浮動小数点数クラス)、 'hello' は str class(文字列クラス) です。

リテラル が 何のクラスのオブジェクトであるか実際に調べます。 type() 関数を使って。

>>> type(3)
<class 'int'>
>>> type(3.0)
<class 'float'>
>>> type('hello')
<class 'str'>

'i', 'number', "number" のように、引用符で囲まれている単語 は 文字列クラス です。

>>> type('i')
<class 'str'>
>>> type('number')
<class 'str'>
>>> type("number")
<class 'str'>
変数もオブジェクト

変数もオブジェクトです。 「そのオブジェクトが何のクラスであるか」は中に代入されてるデータによります。

例えば、 number のように引用符で囲まれてない単語は変数です。 number に 整数 を代入したら、numberは整数クラスです。

変数が何のクラスのオブジェクトであるかを実際に確認します。 type() 関数を使って。

>>> number = 10
>>> type(number)
<class 'int'>
>>> distance = 42.195
>>> type(distance)
<class 'float'>
>>> color = "Brown"
>>> type(color)
<class 'str'>

他のデータ型も見てみましょう。 とりあえず、いろんなクラスのデータがある事だけ知っておけばよいかと思います。

>>> this_is_a_list = [0, 1, 2, 3]
>>> type(this_is_a_list)
<class 'list'>
>>> result_of_tests = {'japanese': 30, 'math': 80, 'physics': 80, 'english': 70, 'geography': 70}
>>> type(result_of_tests)
<class 'dict'>
>>> coordinates = (200, -400)
>>> type(coordinates)
<class 'tuple'>

上の黒い画面はPythonのコンソールの画面です。 Pythonコンソールの起動方法については別の記事に書く予定です。

字下げ:行頭の空白

字下げとは

forループ、条件分岐if のように、 行末が:となっているとき、 その下の行頭に「半角4文字の空白」が入っています。 下のように。

for i in range(3):
    print("これはforループの中の処理")
    print("これもforループの中の処理")
print("これはforループの外の処理")

「行頭に空白を入れること」を 字下げ(indent) と言います。

「forループの中にある処理」 を書くとき、字下げをする必要があります。 字下げしていない場合、それは「forループの外に出た処理」である事を意味します。

インデントによって、プログラムの構造 が表現されています。 Pythonプログラムを書くとき、適切にインデントする事は必須です。 さもなくばエラーがでます。

テキストエディタを使って字下げする

私は Atom という エディタを使っていますが、 行末に:がある場合、自動で字下げしてくれます。 それ以外のとき、上の行の位置に自動でそろえてくれます。

また、Atom には 「字下げのキーボードショートカット」 が割り当てられています。 マウスでテキストを選択したあと、

  • インデント:ctrl を押しながら ] とすれば、コードの塊が右に移動
  • アウトデント:ctrl を押しながら [ とすれば、コードの塊が左に移動

もしくは、Tab キーを押せば、4文字分インデントしてくれます。 私はpythonコンソールを使うとき、タブキーを使って字下げしています。

モジュールとはプログラムの部品

turtleモジュールとは、タートルグラフィックスを使うためのプログラムの部品 です。 ファイル名は turtle.py です。

下のように、モジュールをimportして、モジュール名を printすれば、モジュールの場所が表示されます。

import turtle
print(turtle)

私の場合、turtleモジュール( turtle.py )の置き場所は、 C:\Users\********\AppData\Local\Programs\Python\Python36-32\lib\turtle.py でした(OS:windows10)。

turtleモジュールのソースコードは タートルグラフィックスのドキュメント (左上) からリンクされています。 それによると、ソースコードの行数は4140行です。

インスタンスを作成

  • scr = turtle.Screen() Screenクラス のインスタンスscr を作成
  • ttl = turtle.Turtle() Turtleクラス のインスタンスttl を作成

分かりやすく言い換えるなら、画面と亀(カーソル)を作っています。 画面上でカーソルを動かして、絵を描きます。

画面のインスタンスを作ると、画面が出現します。 亀(カーソル)のインスタンスを作ると、カーソルが画面の中央に現れます。

Screenクラス, Turtleクラス は turtleモジュール の中で定義されています。 だから、turtle.Screen() や turtle.Turtle() のような使い方をして、 それぞれのクラスのインスタンスを作ります。 クラスとは設計図です。

その設計図をもとに、具体的な「画面やカーソル」 を作る事ができます。 それがインスタンス(instance)です。実物のことです。

上のプログラムでは、インスタンスの名前を scr, ttl のようにしました。

Turtleクラスが持ってるメソッド

カーソルは「ペンの色」「ペンの太さ」「向いてる方向」などの属性を持っています。

またカーソルは「前に進む」「向きを変える」「ペンの色を設定する」「ある点に移動する」 などして、カーソル自身を操作(メソッド, method)することが可能です。

ttl.shape('turtle') のように、 「インスタンス名.メソッド名(引数)」みたいな感じでメソッドを使います。

shape() は カーソルの形を 設定するメソッドです。 今回、カーソルの形を亀('turtle') に設定しました(※turtleを引用符で囲むのを忘れないでください)。

「Turlteクラスが持っているメソッド」は turtleモジュールのドキュメント で詳しく述べられています。

コメントの書き方

プログラムの中で # と書いたら、それより右は機械に解釈されません。 だから、そこに好きなコメントを書けます。 下のように。

import turtle # タートルグラフィックス
import tkinter # グラフィカルユーザインターフェイス
import datetime # 基本的な日付型および時間型
import random # 擬似乱数を生成する


#----モジュールの場所を表示させます------
print(turtle)
print(tkinter)
print(datetime)
print(random)

print_modules_locations_20180614.py

プログラムにコメントを書く主な理由は

  • 他人が理解しやすいように
  • コードを書いてる自分が混乱しないように

だと思われます。

私がいま読んでる本のように #--- とコメントを書くと、コメントが目立って分かりやすいです。

プログラムの書き方にはいろんな流派があるので、いろんな人のコードを読むと面白い発見があるかと思います。 また、便利なやり方を自分で思いついたら、ぜひ実践してみてください。

一時的に使用する変数は一文字でもいい

今回、座標を表す変数として、x, y を使いました。 一時的に使う変数は短くてもあまり問題ないと思います。 名前を変更したくなったら、少し面倒になりますが。

「一時的」という定義があいまいですが、 「x,yに数字を代入し、その値を5行に渡って利用する場合」、それは一時的といえると思います。 これは人によるかもしれません。

range()関数

range(4) は、 「0,1,2,3」 の 数列 を返します。 4は含まれません。

>>> list(range(4))
[0, 1, 2, 3]
>>> range(4) == [0, 1, 2, 3]
False
>>> type(range(4))
<class 'range'>

Pythonのドキュメントによると、range() は 「rangeクラスのオブジェクト」 を作る関数です。

rangeクラスのオブジェクト は 等差数列を作るためのデータだけ保存し、必要になったら、計算して順番に数列を返します。 ゆえに、リストのように大量の値を記録する必要がないので、容量が節約されているらしいです。

実際に、range()関数がリストを作るわけではありません。 list(range(4)) のように、リストに変換して出力することもできますが。

forループ

for i in range(4): は 「i=0,1,2,3」 の順番で「繰り返しの処理」をする記述です。

i という数字の値は「繰り返しの処理の中」 で使わなくても良いです。 使わなかったら、同じことを繰り返します。 下のように。

for i in range(4):
    print("同じ事を4回繰り返す")

今回の変数i は 「繰り返しの回数を数えるだけのために用意された」 みたいな感じです。 私はプログラミングを始めたとき、少し奇妙に感じました。そのうち慣れます。

変数iをループの処理のなかで使うこともできます。下のように。

for i in range(4):
    print(str(i+1) + "回目の処理")

今回、forループ(繰り返し処理) に使う変数を i としています。 ループに使う変数 も 一文字 で構わないでしょう。

「頻繁に使用する変数」 を 「少ない文字数」 にしたほうが書きやすいです。 変数の名前を適切に決めて、「何の変数であるか」を分かりやすくするのも重要ですが。

ループ(loop) は 輪 という意味です。 「何回も繰り返し回る輪」をプログラムに書いてるみたいな感じでしょうか。

0 件のコメント:

コメントを投稿

投稿されたコメントは承認後に公開されます。