2024-2I プログラミング1 第03回 講義資料

2024年05月10日(金)1・2時限

1 連絡事項と講義概要

2 前回の復習

前回講義の内容について、要点の「おさらい」をしておきます(少しだけ新規の内容が含まれています)。

2.1 プログラミング学習の「マインド」と「姿勢」

2.2 文字列出力と変数について 15分

ここからは、技術的な内容です。

2.2.1 GoogleColabノートブックの作成 (3分)

GoogleColabにアクセスして OMUID でログインしてください。その後、ノートブックを「新規作成」して PG1-第03回講義.ipynb のように名前を変更してください。ここで、拡張子.ipynbIPYthon NoteBook の略でした。

以下、ノートブックに「コードセル」を追加し、指示に従いプログラムを記述し、実際に実行して、その動作を確認してください。

2.2.2 文字列の出力 (1分)

次のプログラムについて [期待する実行結果] が得られるように書き換えてください。

#【前回復習】文字列の出力
%reset -f
print() # ■■ この文を書き換える ■■

[期待する実行結果]

An eye for an eye, a tooth for a tooth - Code of Hammurabi

2.2.3 変数と組み合わせた文字列の出力 (3分)

次のプログラムについて、[期待する実行結果] が得られるように書き換えてください。「f文字列」を使用するバージョンと、「+演算子」を使用するバージョンの両方を作成してください。

#【前回復習】変数と組み合わせた文字列の出力
%reset -f
word1 = 'eye'
word2 = 'tooth'
print() # ■■ この文を書き換える ■■

[期待する実行結果]

An eye for an eye, a tooth for a tooth - Code of Hammurabi

2.2.4 引用符を含む文字列の出力 (2分)

次のプログラムについて、[期待する実行結果] が得られるように書き換えてください。

#【前回復習】引用符を含む文字列の出力
%reset -f
word1 = 'eye'
word2 = 'tooth'
print() # ■■ この文を書き換える ■■

[期待する実行結果]

"An eye for an eye, a tooth for a tooth" - Hammurabi's Code

上記には、ダブルクォーテーション (半角)シングルクォーテーション/アポストロフィ (半角) の両方が含まれる点に注意してください。

2.2.5 改行を含む文字列の出力 (1分)

次のプログラムについて、[期待する実行結果] が得られるように書き換えてください。この際、第05行目print 文の変更だけで目的の処理を完結させてください。

#【前回復習】改行を含む文字列の出力
%reset -f
word1 = 'eye'
word2 = 'tooth'
print() # ■■ この文を書き換える ■■

[期待する実行結果]

"An eye for an eye, a tooth for a tooth" 
  - Hammurabi's Code

2.2.6 print関数に複数の引数を与えた場合の挙動 (2分)

まずは、次のプログラムを実行して、その動作を確認してください。つづいて、[期待する実行結果] が得られるように書き換えてください。

# print関数に複数の引数を与えた場合の挙動
%reset -f
print('Python','C/C++','Java','PHP',sep='♡')

[期待する実行結果]

Python と C/C++ と Java と PHP

出力には「と」の前後に半角スペースが含まれることに注意してください。sep は Separator の略です。

2.2.7 EX: ANSIエスケープシーケンスによる文字列装飾

(時間に余裕があれば取り組んでください)

ANSIエスケープシーケンスを利用して、次の [期待する実行結果] のような 装飾付き文字列 (青文字、青背景の白文字) が得られるようなプログラムを記述してください。

[期待する実行結果]

img

3 変数のクリア

(ここからが今回の講義の内容になります)

GoogleColab において、あるコードセルで作成(設定)した「変数」は 他のコードセルにも引き継がれます。実際に確認してみましょう (試してみましょう)。

コードセルを新規作成して次のプログラムをコピペして実行します。コードセルの「実行」には アイコンの押下ではなく、積極的に Ctrl+Enter のショートカットキーを使用してください。

word = '無駄!'
print(word*10)

次に、別のコードセルを新規作成して、次の pg2.py の内容をコピペして実行します。pg2.py第01行目 では、あえて変数名の タイポ をしています。つまり、変数名を word ではなく wrod にしています。

wrod = 'オラ'
print(word*8)

上記プログラムを実行すると、第01行目 で文字列をセットしている変数名 wrod と、第02行目 で参照している変数名 word が違うので NameError: name 'wrod' is not defined のようなエラーがでるだろう と期待しますが、実際の結果はそうはなりません。

次のような実行結果が得られたはずです。

無駄!無駄!無駄!無駄!無駄!無駄!無駄!無駄!

(なお、元ネタは ジョジョの奇妙な冒険です。)

先に実行したセルで作成された変数 word が内部的に残っているのでエラーは発生しないものの、意図した結果が得られない という状況になります。

今回は、変数名に間違いがあることに気づいているために問題ありません。しかし、間違いに気づいていないときに「エラーは発生しないものの、意図した結果が得られない」という状況は、非常に厄介なものとなります。実際、このようなことで何時間も悩んだり、プログラミング学習に挫折したりする初心者も珍しくありません。

コードセルを抜けても 変数が生き残っていること は非常に便利な機能なのですが、状況によっては望ましくありません。そのような状況で役立つのが、変数をオールクリアするための %reset -f になります。既に第01回の講義資料から登場しています (解説されるのを待つことなく、自分で検索等して解決した人は大変に素晴らしいです )。

実際に、%reset -f の働きを確認してみましょう。さきほどのコードセルを次のように書き換え (つまり %reset -f を追記し) 、実行してみてください。

%reset -f
wrod = 'オラ'
print(word*8)

今度は、無事に エラーが発生する ようになりました。エラーが発生することで「不具合の原因がどこにあるか」のヒントが得られるようになりました。

3.1 演習

%reset -f%reset に書き換えて実行し (-fオプションを「抜いて」実行し)、どのように動作が変わるかを確認してください。

コマンドのオプション

一般にコマンドの「オプション」の -f は「force (強制する)」を意味します。例えば、Linuxにおけるファイル削除のコマンド rm は、通常「本当に削除してよいか」の旨の確認がされますが rm -f のようにオプションをつけると「確認なし」で削除が実行されます。

よって、次のような -f オプションをつけたコマンドを安易に実行しないように十分に注意してください。

sudo rm -rf / --no-preserve-root

OS (Linux) が吹っ飛びます。

3.2 補足: マジックコマンド

GoogleColab のコードセルのなかで % から開始する文をマジックコマンドといいます。マジックコマンドは、Python の文・機能ではなく、GoogleColab (Jupyter) の文・機能であり、(Colab以外の) ローカルの Python開発環境 では使用できません。

一度は「Colab マジックコマンド」で検索してみてください。開発を効率的に進めることができる様々なマジックコマンドが存在しています。

4 変数の確認

GoogleColab では、参照可能な変数 (定義されている変数)%who というマジックコマンドで確認することができます。

実際に確認してみましょう。コードセルを新規作成して、次のプログラムを実行してください。

apple = 'りんご'
banana = 'バナナ'

次に、別のコードセルを新規作成して、次のマジックコマンドを実行してください。

%who

現時点で定義済みの変数が表示されます。また、%whos%who_ls のマジックコマンドについても動作を確認してみてください。

その後、%reset -f を実行後、再度、各マジックコマンド (%who%whos) を実行して結果を確認してみてください。

5 変数に「数値」を代入して取り扱う

5.1 導入

ここまでは「変数」に文字列 (文字列リテラル) を代入するプログラムを扱ってきました (リテラルとは?)。その際、注意すべきことは、次のように 文字列をダブルクォーテーション、または、シングルクォーテーションで囲んで扱う (表現する) ということでした。

%reset -f
apple = 'りんご'
banana = "バナナ"
toeic_score = '350' # 文字列としての350
print( "apple = " + apple )
print( f'3-banana => {banana * 3}' )
print( f'TOEICスコア倍増! 目指せ{toeic_score * 2}')

特に、上記を実行した際、07行目の文によって出力される文字列に注意してください (どのような結果になるか、予想の上、実行してみてください)。ここで変数 toeic_score に格納されている「350」は「数値」ではなく 文字列 であるため、期待するような振る舞いはしません。

これは、f文字列の内部の特有の振る舞いではなく、次のようにプログラムを書いた場合でも同じです (期待するような文字列出力を得ることはできません)。

%reset -f
toeic_score = '350' # 文字列としての350
toeic_double_score = toeic_score * 2
print( '目指せ' + toeic_double_score )

5.2 変数に数値を代入

ここからは、変数に数値 (\(\neq\)文字列) を代入することを考えていきます。

中級者向け: 厳密には代入ではなくバインド(束縛)

前回も解説したように「整数値を変数に代入する」という表現は厳密には正しくありません (束縛する(バインドする)という表現が正しいです)。ただし、ここでは初心者向けに厳密さをある程度犠牲にして分かりやすさを重視して表現していることをご理解ください。

詳しくは 小山高専・技術支援室 を参照してください。

変数に数値 (\(\neq\)文字列) を代入するときは、次のように シングル/ダブルクォーテーションでは「囲まず」 にイコール = の右辺に数値を与えます。

%reset -f
toeic_score = 350 # "350" や '350' にしないこと
print( f'TOEICスコア倍増! 目指せ{toeic_score * 2}')

また、pi=3.14 のように 小数部を含む実数 を変数に代入することもできます。

なお、次のように f文字列 に埋め込まず、print関数の引数に直接変数を与えて、その内容を出力すること (表示すること) もできます。

%reset -f
toeic_score = 350
toeic_double_score = toeic_score * 2
print( toeic_score ) # print関数の引数に、直接、変数を与えている
print( toeic_score, toeic_double_score )

また、次のように、直接、計算式を与えることもできます。

%reset -f
print( 350 * 2 )

5.3 文字列と数値を組み合わせて出力する場合の注意点

f文字列を使わずに、+ 演算子を使って「数値」と「文字列」を組み合わせるときは、以下の点に注意してください。

まず、f文字列であれば、以下のように問題なく「文字列」と「数値」を組み合わせることができます。

%reset -f
toeic_score = 350 # 変数に格納されるのは「文字列」ではなく「数値」
print( f'私のTOEICスコアは {toeic_score} です。')

次に、以下のプログラムをのように + 演算子を使って「文字列」と「数値」を結合しようとすると、TypeError: can only concatenate str (not "int") to str というが発生します。実際に確認してみてください。

%reset -f
toeic_score = 350 # 変数に格納されるのは「文字列」ではなく「数値」
print( '私のTOEICスコアは ' + toeic_score + ' です。')

このエラーは「文字列」と「数値」という異なる種類のものを「加算」「結合」しようとしたために発生します。+ 演算子は、基本的に「文字列同士」や「数値同士」のように同種のものにしか適用できません。

この問題を解決するためには、次のように str 関数を使用して、変数 toeic_score に格納された「数値」を「文字列」に変換したうえで、+ 演算子を適用する必要があります。str 関数は、String (文字列) が由来です。

%reset -f
toeic_score = 350 # 変数に格納されるのは「文字列」ではなく「数値」
print( '私のTOEICスコアは' + str(toeic_score) + 'です。')

5.3.1 定着確認1

次のプログラムは、実行時にエラーが発生します。このエラーの原因を特定し、プログラムを修正して正しく実行できるようにしてください。

%reset -f
name = 'ヨシヒコ'
age = 16
print('それは' + name + 'が' + age + '歳になる誕生日のことであった。')

5.3.2 定着確認2

次のプログラムは、実行時にエラーが発生します。このエラーの原因を特定し、プログラムを修正して正しく実行できるようにしてください。

%reset -f
future = 5
age = 16
print(future + '年後、お主が ' + age + future + ' 歳になるとき、', end='')
print('魔王が復活するとの言い伝えがあるのじゃ。')

6 GoogleColabノートブックの共有設定

GoogleColab のノートブックは、次の手順で公開範囲を変更して、共有リンク (URL) を得ることができます。以降、課題 (宿題) として、公開リンクを提出してもらうことがあります。

ノートブックを作成後、画面右上の「共有」を選択します。

img

初期状態では「自分だけ」が閲覧・編集ができるノートブックになっています。以下、以下の手順で、大阪公大の組織アカウントを持っている人が閲覧できるように設定変更します。

一般的なアクセス」の項目を「制限付き」から「大阪公立大学」に変更します。

img

以上の設定により、大阪公大の組織アカウントのユーザーが閲覧可 (編集は不可) なノートブックになりました。「リンクをコピー」のボタンを押下すると、クリップボードに 共有リンク (URL) が取得できます。

img

6.0.1 演習

現在のノートブック (PG1-第03回講義.ipynb) の公開範囲 (閲覧) を、大阪公大の組織アカウントに設定して、その 共有リンク (URL) を指定の位置に提出してください。

7 Pythonで利用可能な数値リテラル

Pythonでは、toeic_score = 350pi=3.14 以外にも、次のような数値リテラル (数値の表記) を使って変数に値を代入することができます。

7.1 桁数の大きな値

桁数の大きな値 (例えば、300,000,000 = 3億) は、次のように与えることができます。

%reset -f
x1 = 300000000 # ノーマルな方法(ミスしやすい)
print(f'x1 = {x1}')

x2 = 300_000_000  # アンダーバーを数値区切りに利用
print(f'x2 = {x2}')

x3 = 3e+8 #「3e+8」は「3×10^8」の意味
print(f'x3 = {x3}')

演習 \(5\mu\ (\ =5\times10^{-6}\ )\) は、どのような数値リテラルとなるか。

%reset -f
x4 = 5e-6
print(f'x4 = {x4:f}')

上記、第03行目:f は書式指定子となります。詳細は後述

7.2 2進数表記の値

2進数表記の値 ( Binary: バイナリ ) は、次のように先頭に 0b を付けて与えることができます (先頭に付ける文字を prefix (プレフィックス) や 接頭辞/接頭辞 と表現します) 。また、10進数の場合と同様に、任意の位置 (好きな位置) に _ を入れることができます。

%reset -f
x1 = 0b1010 # 1010 => 8 + 2 = 10
print(f'x1 = {x1}')

x2 = 0b_1010 # 1010 => 8 + 2 = 10
print(f'x2 = {x2}')

x3 = 0b_0011_1010 # 0011 1010 => 32+16+8+2=58
print(f'x3 = {x3}')

注意

第01講義、第02回講義でも注意しましたが、解説を受ける / 解説を読む だけではなく、必ず手を動かして自分自身で「試してみること」「検証してみること」、また「例外はないのか?などについて考えてみること」を忘れないでください。

例えば、プレフィックスであれば「0B のような大文字でもよいのか」「00Bのようなゼロ2連続でもよいのか」、 数値区切りのアンダーバーであれば「2個連続で使えるのか」「数値リテラルの先頭や末尾でも使えるのか」「プレフィックスの途中で 0_b_1100 のように使えるのか」のようなことが発想ができ、結果を予想し、それを試して、規則性などを見いだせる ようになってください (このようなことができる人が最終的に高いスキルを習得できます)。

同時に、いま学んでいることが「日常の生活や教科学習では、どのように利用できそうか」「自分がつくりたいモノ (例えばゲーム) にどのように利用できそうか」という視点も常に持つようにしてください。

7.3 16進数表記の値

16進数( Hexadecimal: ヘクサデシマル ) は、次のように与えることができます。16進数の「A」から「F」は、大文字でも小文字でも どちらでも表記できます。

%reset -f
x1 = 0xFF
print(f'x1 = {x1}')

x2 = 0xff
print(f'x2 = {x2}')

x3 = 0x_ffEE6a # 大文字と小文字の混合
print(f'x3 = {x3}')

8 四則演算

整数」または「小数を含む実数」が数値が格納された変数に対しては、次のように四則演算をすることができる。

%reset -f
a, b = 7, 2  # a=2 と b=6 を1行で記述

# 加算
x = a + b   #「x1=a+b」のようにスペースを含めず記述も可
print(f'(1) {a}+{b}={x}')

# 減算
x = a - b 
print(f'(2) {a}-{b}={x}')

# 乗算
x = a * b  # 乗算(掛け算)。「*」はアスタリスクと読む。
print(f'(3) {a}*{b}={x}')

# 除算
x = a / b  # 除算(割り算)
print(f'(4) {a}/{b}={x}')

x = a % b  # 何を計算しているか検証せよ。
print(f'(5) {a}%{b}={x}')

x = a // b  # 何を計算しているか検証せよ。
print(f'(6) {a}//{b}={x}')

上記の 第20行目第23行目 については、変数の値を変更しながら「何を計算しているのか」を検証してください。特に、変数に格納される値が 「小数」や「負数」 となったときに、どのような挙動を示すのか、検証してください。

8.1 演習

変数 a に10、変数 b に5、変数 c に2を代入して次の値を計算してください。さらに、正しく計算できているかどうかを、手計算 や Excel を使用した計算や、周囲の学生と突き合わせることで検証してください。

なお、\(3(x+1)(x+2)\) のような計算は 3*(x+1)*(x+2) のように * を明示する必要があるので注意してください。

\[ (1)\ \ \ 6ab^{2} \]

\[ (2)\ \ \ -3(a+b)\{(a+c)-(b+c^2)\} \]

\[ (3)\ \ \ -\frac{3b^2}{6a+2c} \]

注意

ChatGPTなどの生成AIの登場により「(正当性の保証はないものの) とりあえずの答えをだすこと」は、ほぼ誰でも可能な時代となりました。そのうえで、重要なことのひとつとして「解の検証」が挙げられます。

「情報1」や「情報2」の授業でも伝えているように「技術者には自分自身で解の妥当性を検証し、それに責任を負うことが求めれる」ということを意識して、日頃から、そのための訓練や習慣づけを行うことが重要です。

9 出力の書式指定

変数に格納した数値を、文字列として出力する際、次のように 書式 (フォーマット) を指定することができます。f文字列のなかで、: に続けて「書式指定子」というものを記述します。

%reset -f
a = 45 # 整数値
print(f'a={a}')       # 書式指定なし
print(f'a={a:.2f}')   # 小数点以下桁数指定
print(f'a={a:b}')     # 2進数 1+4+8+32
print(f'a={a:_b}')    # 2進数 区切り文字あり
print(f'a={a:09_b}')  # 2進数 ゼロ埋め・出力桁数指定
print(f'a={a:x}')     # 16進数 13+32
print(f'a={a:X}')     # 16進数 大文字
print(f'a={a:04X}')   # 16進数 ゼロ埋め

小数を含む場合の例を示します。

特に 第04行目 のように桁数を指定するときは、四捨五入されるのか、切り捨てられるのか、切り上げられるのか、それともそれ以外なのか、 を予想し、検証してください。

%reset -f
a = 0.62184 # 実数
print(f'a={a}')      # 書式指定なし
print(f'a={a:.3f}')  # 小数点以下の桁数指定
print(f'a={a:.4f}')  # 小数点以下の桁数指定
print(f'a={a:e}')    # 指数表示
print(f'a={a:.3e}')  # 指数表示+桁数指定
print(f'a={a:.3E}')  # 指数表示
print(f'a={a:%}')    # パーセント
print(f'a={a:.1%}')  # パーセント+桁数指定

このほかにも多数の書式が存在します。必要に応じて「python f文字列 書式指定」などでウェブ検索して適用できるようになっておく必要があります。

頻繁に使用する書式以外は、暗記する必要はありませんが、その存在を意識して必要に応じて利用できるようになっておいてください。

9.1 補足1

単位のSI接頭辞(SI接頭語)に関連した変換は、次のようにできます。

%reset -f
length = 42195 # ここでは 42195メートルの意味
print(f'{length:,}(m)は、{length*1e-3}(km)です')
print(f'{length:,}(m)は、{length/1000}(km)です')

9.2 補足2

f文字列は、print関数の引数として使用することが多いですが、独立して使用することもできます。

%reset -f
month = 5
day = 10
date = f'{month:02}{day:02}日'
print(f'こんにちは。きょうは{date}です。')

10 丸め誤差

「情報2」の第03回の授業で学習したように、10進数表記では有限小数となる数値が、2進数表記では無限小数になることがあり、また、コンピュータのメモリ (記憶領域) が有限であることから、コンピュータで小数を扱う場合は 丸め誤差 が生じます。これは Python でも同様で、金融計算を扱う場合には、特に注意する必要があります。

%reset -f
x = 2.40 - 2.25   # 計算結果は 0.15 のはず
print(f'x = {x}')

実行結果は、次のようになります。

x = 0.1499999999999999

中級者向け: decimalモジュール

decimalモジュール を使用することで、計算に「0.1」や「0.2」を含む場合でも誤差なく正確な計算ができるようになります。ただし、通常の計算にdecimalモジュールを使うことには相応のデメリットがあります (考え、調べて、検証してみましょう)。

%reset -f
from decimal import Decimal
x = Decimal('2.4')-Decimal('2.25')
print(f'x = {x:.20f}')

11 べき乗の計算

べき乗の計算には、** 演算子を使用します。なお、Excelではべき乗の計算に ^ を使用しますが、それと混同しないようにしてください。Python では ^ 演算子は、ビット単位の排他的論理和 (XOR) の計算に使われれます。

%reset -f
a, b = 2, 6  # a=2 と b=6 を1行で記述する方法
x = a ** b   # aのb乗(2の6乗)を計算
print(x)

上記では変数を経由していますが、次のように変数を使わずに同じ出力を得ることもできます。

%reset -f
x = 16 ** 2
print(x) # => 256
%reset -f
print(16**3) # => 4096
%reset -f
16**4 # => 65536

また、** 演算子を使用することで平方根や、3乗根、4乗根を求めることもできます。

\[ \sqrt{256} = 256^{1/2} = 256^{0.5} = 16\]

%reset -f
a, b = 2, 0.5
x = a ** b   # aのb乗。0.5乗=1/2乗=平方根
print(x)

12 課題01

PG1-第03回講義.ipynb の末尾に次の内容の「テキストセル」を作成し、それ以降の位置に「コードセル」を追加して、以下の各設問に取り組んでください。

# **プログラミング1 課題01**

- 氏名: 高専太郎 
- 出席番号: 99

12.1 設問1

CPUのクロック周波数が2.1GHzのとき、そのクロック周期が何秒になるかを計算せよ。なお、X.XXXe-XX のような指数の形式による出力と、SI接頭語 ( us / ns / ps ) を用いた XXXX(ps) のような形式による出力の両方を得ること。

# 設問1
%reset -f

12.2 設問2

電気信号が伝わる速さは「光速」とほぼ同じで約 \(3\times 10^{8}\) (m/s) である。CPUのクロック周波数が \(2.8\)(GHz) のとき、そのクロック周期に相当する時間のなかで電気信号が進む距離を XXX.X(cm) の形式で出力せよ。小数点以下は1桁で答えること。

12.3 設問3

次の16進数を2進数と10進数に変換せよ。

\[(1)\ \ \ (\mathrm{FFFF}\ \mathrm{FC00})_{16}\] \[(2)\ \ \ (\mathrm{1000}\ \mathrm{0101})_{16}\]

12.4 設問4

次の2進数を16進数に変換せよ。

\[(1)\ \ \ (0011\ 0101\ 1010)_{2}\] \[(2)\ \ \ (1001\ 0110\ 0011)_{2}\]

12.5 設問5

現在までに学習した「物理」や「数学」、その他の「専門科目」に関する問題 (主に計算問題) を テキストセル に記述せよ。さらに、その問題を Python を使って解け (解くためのプログラムをコードセルをに記述せよ)。

なお、GoogleColab のテキストセルはマークダウン形式で記述可能であり、マークダウン形式では LaTeX形式の数式記述が可能である