基本情報のサンプル問題で Python の基礎知識をチェック | 午後問題の歩き方


2020-09-04 更新

error

この記事は基本情報技術者試験の旧制度( 2022 年以前)の記事です。
この記事の題材となっている「午後問題」は現在の試験制度では出題されません。 ご注意くださいませ。

令和 2 年度 春期 基本情報技術者の午後試験で、プログラミング言語に Python を選択しようと思っている人は、「自分の持っている知識で大丈夫だろうか?」と心配しているでしょう。

現時点で、基本情報技術者試験の Python に関する情報は、シラバスサンプル問題しかありません。

前回の記事では、シラバスで Python の知識を確認しました。今回は、サンプル問題のプログラムで Python の知識を確認してみましょう。

error 本記事ではわかりやすいよう、問題にシンタックスハイライトを入れ、問題の一部を省略するなどしています

サンプル問題の内容

プログラムを見る前に、サンプル問題の内容を簡単に説明しておきます。

"R3;R4;F100;T90;E0;F100;E0" という形式の命令列を解釈して、x – y 平面に図形の描画を行うプログラムです。

個々の命令は、1 文字の英字で示された命令コードと、数値で示された数値パラメタから構成され、セミコロン( ; )が命令の区切りを示します。

命令コードと数値パラメタの説明を以下に示します。

図 命令コードと数値パラメタの説明
命令コード 数値パラメタ 説明
F 長さ マーカを現在の進行方向に数値パラメタで指定した長さだけ進め、移動元から移動先までの線分を描く。
T 角度 マーカの進行方向を、数値パラメータが正の場合は反時計回りに、負の場合は時計回りに、数値パラメタの角度(度数法)だけ回転する。
R 繰返し回数 繰返し区間の開始を示す。この命令と対になる命令コード E との間を、命令コード R の数値パラメタの回数だけ繰り返す。
E 0 繰返し区間の終了を示す。数値パラメタは、常に 0 である。

"R3;R4;F100;T90;E0;F100;E0" という命令列は、 "R3" "R4" "F100" "T90" "E0" "F100" "E0" という 7 個の命令から構成されていて、それぞれ

  1. 「 3 回の繰返しの開始」
  2. 「 4 回の繰返しの開始」
  3. 「長さ 100 の線分を描く」
  4. 「反時計回りに 90 度回転する」
  5. 「 4 回の繰返しの終了」
  6. 「長さ 100 の線分を描く」
  7. 「 3 回の繰返しの終了」

を意味しています。

マーカは、初期状態で ( 0, 0 ) の位置にあり、進行方向はx 軸の正方向になっています。したがって、この命令列を解釈することで、以下の 3 つの四角形描画されます。

図 命令列の解釈によって描画された図形の例

プログラムの全体構造と実行方法

それでは、プログラムを見てみましょう。

Python では、プログラムの構成要素を、関数またはクラスという形式にします。

関数やクラスは、あらかじめ用意されているものを利用する場合と、自分で作る場合があります。

標準で用意されている関数やクラスは、すぐに使えますが、そうでないものは、プログラムの先頭で import 文を使って、「この関数やクラスを使います」ということを示してから使わねばなりません。

 

以下に、プログラムの全体構造を示します。

図 プログラムの全体構造
announcement横にスクロールできます
(以下、すべてのプログラムも同様)
import math # mathを使う
import matplotlib.pyplot as plt	# matplotlib.pyplotをpltという別名で使う

# 自分でparse関数を作る
def parse(s):
︙

# 自分でMarkerクラスを作る
class Marker:
︙

# 自分でdraw関数を作る
def draw(s):
︙

先頭にある import で、数学関連の関数を提供する math と、描画の機能を提供する matplotlib.pyplot を使うことを示しています。

matplotlib.pyplot は、名前が長いので、as plt で plt という別名をつけています。これによって、matplotlib.pyplot を plt という名前で使えるようになります。

自分で作っている構成要素は、parase 関数、Marker クラス、および draw 関数です。それぞれの内容は、あとで説明します。

 

このプログラムには、プログラムの実行開始位置となるものがありません。

それでは、どうやって実行するのかというと、端末( Windows ではコマンドプロンプト)で Python のインタプリタを起動し、任意の引数を指定して draw 関数を実行するのです。

draw 関数の引数に、描画の命令列を指定します。

以下は、プログラムを fesample.py というファイル名で保存し、Python インタプリタを起動して、fesample を import し( import するときには、ファイル名の拡張子の .py を指定しません)、 "R3;R4;F100;T90;E0;F100;E0" という引数を指定して draw 関数を実行した例です。

図 Python インタプリタで draw 関数を実行した例
>>> import fesample import draw
>>> draw("R3;R4;F100;T90;E0;F100;E0") 
[] 
[{'opno': 0, 'rest': 3}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 4}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 4}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 4}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 3}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 3}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 3}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 2}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 2}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 2}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 1}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 1}] 
[{'opno': 0, 'rest': 3}, {'opno': 1, 'rest': 1}] 
[{'opno': 0, 'rest': 3}]

これによって、先ほど示した 3 つの四角形描画されます。端末に表示されているのは、デバッグ用の情報です。

info 編集部 補足
Python をブラウザからオンラインで実行できる「 JupyterLab 」でも試せます

parse 関数の内容

以下は、parse 関数の内容です。ここでは、説明の都合で、行番号を付けてあります。

このプログラムで使われている言語構文から、Python の基礎知識を確認してみましょう。

def parse(s):
  return [(x[0], int(x[1:])) for x in s.split(';')]
確認 1 関数の定義と戻り値 1 行目、2 行目
関数は、 def 関数名(引数): というブロックで定義し、 return 戻り値 で戻り値を返します。
確認 2 str クラスの split メソッド
str クラスの split("区切り文字") メソッドは、文字列を区切り文字で分割したリストを返します。
たとえば、 "R3;R4;F100;T90;E0;F100;E0" という文字列を  ;  という区切り文字で分割すると、 ['R3', 'R4', 'F100', 'T90', 'E0', 'F100', 'E0'] というリストが得られます。
確認 3 for 文
繰返しを表す for 文は、 for 変数 in イテラブル という構文で、イテラブル( range 関数、リスト、タプル、文字列など)から繰返し要素を取り出して変数に格納します。
たとえば、イテラブルに ['R3', 'R4', 'F100', 'T90', 'E0', 'F100', 'E0'] というリストを指定すれば、リストの要素を順番に取り出して変数に格納します。
確認 4 リスト内包表記 2 行目
リスト内包表記は、リストの要素を効率的に(短いプログラムで)作成する表記です。
[式 for 変数 in イテラブル] という構文で、for 文で変数に取り出されたすべての要素に、同じ式を適用し、その適用結果をリストの要素とします。
たとえば、

 [(x[0], int(x[1:])) for x in ['R3', 'R4', 'F100', 'T90', 'E0', 'F100', 'E0']] 

というリスト内包表記では、

 [('R', 3), ('R', 4), ('F', 100), ('T', 90), ('E', 0), ('F', 100), ('E', 0)] 

というリストが作成されます。

確認 5 リストとタプル
リストは、 [要素1, 要素2, ・・・, 要素n] のように、要素を [ ] で囲みます。
タプルは、 (要素1, 要素2, ・・・, 要素n) のように、要素を ( ) で囲みます。
リストの要素は、値を変更できますが、タプルの要素は、値を変更できません。
タプルを要素としたリストを作ることもできます。たとえば、

[('R', 3), ('R', 4), ('F', 100), ('T', 90), ('E', 0), ('F', 100), ('E', 0)] 

は、 (文字列, 整数) というタプルを要素としたリストです。

確認 6 文字列から 1 文字を取り出す 2 行目
文字列[位置] という構文で、文字列から 1 文字を取り出せます。位置は、先頭を 0 として指定します。
たとえば、 x = " F100" という文字列において、 x[0] は、先頭の “F” を取り出します。
確認 7 文字列から部分文字列を切り出す 2 行目
文字列[開始位置:終了位置:ステップ] という構文で、文字列の開始位置から終了位置 – 1 までステップごとに、部分文字列字を切り出せます(この機能を「スライス」と呼びます)。
終了位置を省略すると、末尾まで切り出します。ステップを省略すると、1 文字ずつ切り出します。たとえば、 x = "F100" という文字列 x において、 x[1:] は、1 文字目から末尾まで 1 文字ずつ切り出すという意味なので、 “100” という部分文字列が切り出されます。
確認 8 int 関数
int 関数は、引数で指定されたオブジェクトを整数に変換します。たとえば、 int("100") は、 "100" という文字列を、 100 という整数に変換します。

Marker クラスの内容

以下は、Markerクラスの内容です。ここでも、説明の都合で、行番号を付けてあります。

このプログラムで使われている言語構文から、Python の基礎知識を確認してみましょう。

図 Marker クラスの内容
class Marker:
    def __init__(self):
        self.x, self.y, self.angle = 0, 0, 0
        plt.xlim(-320, 320)  # x軸の表示範囲を設定
        plt.ylim(-240, 240)  # y軸の表示範囲を設定

    def forward(self, val):
        # 度数法で表した角度を,ラジアンで表した角度に変換
        rad = math.radians(self.angle)
        dx = val * math.cos(rad)
        dy = val * math.sin(rad)
        x1, y1, x2, y2 = self.x, self.y, self.x + dx, self.y + dy
        # (x1, y1)と(x2, y2)を結ぶ線分を描画
        plt.plot([x1, x2], [y1, y2], color='black', linewidth=2)
        self.x, self.y = x2, y2

    def turn(self, val):
        self.angle = (self.angle + val) % 360

    def show(self):
        plt.show()  # 描画結果を表示
確認 9 クラスの定義 1 行目
クラスは、 class クラス名: というブロックで定義します。
確認 10 メソッドの定義と self の役割 3 行目、7 行目、17 行目、20 行目
メソッドは、クラスのブロックの中で、 def メソッド名(引数): というブロックで定義します。
メソッド(インスタンスメソッド)の第一引数には、現在のインスタンスの参照を格納する引数を置きます。この引数は、慣例として self という名前にします。
確認 11 インスタンスの生成と __init__ 関数 の役割 2 行目
クラスのインスタンスは、 インスタンス名 = クラス名(引数) という構文で生成します。
インスタンスの生成時に、インスタンスが持つ __init__ 関数が自動的に呼び出されるので、そこで初期化処理を行うことができます。 self.インスタンス変数名 = 値 という処理を行えば、インスタンス変数に初期値を設定できます。
確認 12 タプルのアンパック 3 行目、12 行目、15 行目
たとえば、 (1, 2, 3) という 3 つの要素を持つタプルがあった場合、 x, y, x = (1, 2, 3) という代入で、右辺のタプルの 3 つの要素を、左辺の 3 つの変数に順番に代入でき、これを タプルのアンパック と呼びます。
タプルを囲む ( ) は、省略できるので、同じことを x, y, x = 1, 2, 3 と記述することもできます。
確認 13 matplotlib.pyplot の使い方 4 行目、5 行目、14 行目、21 行目
matplotlib.pyplot は、描画を行う様々なメソッドを提供しています。
ここでは、matplotlib.pyplot に plt という別名を付けているので、 plt.メソッド名(引数)という構文で、メソッドを使えます。
たとえば、直線を描画する場合は、はじめに、 plt.xlim(下限値, 上限値) plt.ylim(下限値, 上限値) で、x – y 平面の x 軸と y 軸の表示範囲をします。
次に、

 plt.plot([x1, x2], [y1, y2], color="色", linewidth=幅) 

で、 ( x1, y1 ) と ( x2, y2 ) を結ぶ直線を、color に指定された色と、linewidth に指定された幅で、描画します。
ただし、この時点では、まだ画面には表示されません。必要な描画がすべて終わったら、最後に plt.show() で描画の内容を画面に表示します。

確認 14 math の使い方 9 行目、10行目、11 行目
math は、数学関連の様々な関数を提供しています。
ここでは、mathに別名を付けていないので、 math.関数名(引数) という構文で、関数を使います。
radians 関数は、引数で指定された度数法の角度をラジアン単位に変換します。
cos 関数は、引数で指定されたラジアン単位の角度のコサイン値を求めます。
sin 関数は、引数で指定されたラジアン単位の角度のサイン値を求めます。

draw 関数の内容

以下は、draw 関数の内容です。ここでも、説明の都合で、行番号を付けてあります。

このプログラムで使われている言語構文から、Python の知識を確認してみましょう(先ほど「 parase 関数の内容」説明した構文は、取り上げません)。

図 draw 関数の内容
def draw(s):
    insts = parse(s)
    marker = Marker()
    stack = []
    opno = 0
    while opno < len(insts):
        print(stack)
        code, val = insts[opno]
        if code == 'F':
            marker.forward(val)
        elif code == 'T':
            marker.turn(val)
        elif code == 'R':
            stack.append({'opno': opno, 'rest': val})
        elif code == 'E':
            if stack[-1]['rest'] > 1:
                opno = stack[-1]['opno']
                stack[-1]['rest'] -= 1
            else:
                stack.pop()  # stackの末尾の要素を削除
        opno += 1
    marker.show()
確認 15 空のリストの作成 4 行目
変数 = [] という構文で、空のリストを作成できます。
確認 16 リストへの要素の追加と削除 14行目、20 行目
append(要素) メソッドで、リストの末尾に要素を追加できます。pop() メソッドで、リストの末尾の要素を取り出して削除できます。
確認 17 while 文
while 条件: というブロックは、繰返しを表します。ブロックの中にある処理は、条件が True である限り実行されます。
確認 18 if 文
if 条件: というブロックは、条件が True のときに実行されます。

このブロックの後に elif 条件: というブロックを任意の数だけ続けることができ、その前にある条件が False であり、そこにある条件が True のときに実行されます。
最後に else: というブロックを 1 つだけ追加することができ、その前にある条件がすべて False のときに実行されます。

確認 19 print 関数 7 行目
matplotlib.pyplot による図形の描画は、GUI のウインドウの中で行われますが、print(データ) 関数によるデータの表示は、端末の中で行われます。7 行目の print(stack) は、デバッグ用の情報を端末に表示しています。
確認 20 == 演算子 9 行目、11 行目、13 行目、15 行目
== 演算子は、値が等しいときに True を返します。
確認 21 辞書 14 行目
{キー1:値1, キー2:値2, ・・・, キーn:値n} という構文で、辞書を作成できます。

辞書は、キーと値のペアを要素として、添字ではなく、キーを指定することで、要素を取得できます。

確認 22 辞書のリスト 16 行目、17 行目、18 行目
リストは、任意のオブジェクトを要素にできるので、タプルを要素としたリストや、辞書を要素としたリストを作ることができます。

このプログラムの stack というリストは、辞書のリストです。 stack[リストの添字][辞書のキー] という指定で、リストにおいて添字で指定した位置にある辞書から、辞書のキーで指定した値(辞書のキーとペアの値)を取り出せます。

確認 23 リストのマイナスの添字 16 行目、17 行目、18 行目
リストの添字をマイナスにすると、末尾から要素を指定できます。末尾は、 – 1 で表します。
16 行目、17 行目、18 行目で、リストの添字を -1 にしているのは、末尾から取り出すことで、スタックを実現しているからです。

いかがでしたか。ここで示したサンプル問題のプログラムの内容が「余裕でわかるぜ!」なら心配ありませんが、「わからないことだらけだ!」なら Python の言語構文の学習が必要です。

試験まで、あせらずにコツコツと学習を続けてください。プログラミング言語の習得には、時間がかかりますので、「あせらず」「コツコツ」が重要です。

 

それでは、またお会いしましょう!

 

label 関連タグ
科目A試験は、
免除できます。
独習ゼミで科目A試験を1年間免除して、科目B試験だけに集中しましょう。
免除試験を受けた 74.9% の方が、
科目A免除資格を得ています。
科目A免除試験 最大 2 回の
受験チャンス !
info_outline
科目A免除試験 最大 2 回の
受験チャンス !
詳しく見てみるplay_circle_filled
label これまでの『午後問題の歩き方』の連載一覧 label 著者