プログラミング ワークショップ - 超々入門編 Vol.3


本題の前に


位置付け・前提

本記事は、社内ワークショップ のために用意したものです。そのため、次の前提で進めることをご理解ください。


本ワークショップの目的

参加者が必要に併せて自学できる入口に立つ ことを目的とします。

  • 実用的なプログラミングを ハンズオン形式 で実行して、理解を深めます。
  • 本ワークショップだけで、あらゆるプログラムがすいすい組めるようになるわけではありません。
  • 後日にプログラミングで何かを作ろうとしたときに、自分で調べて製作できるようになることを目指します。
  • なんかこういうもんだ、という感じで軽く頭に残れば大丈夫と考えましょう。

ワークショップの進め方

ワークショップは、基本的にハンズオンを中心に進めます。(一部解説は入れます)

  • ご自分の業務用途のパソコンを利用してください。
  • 基本的には「写経」を原則とします。
    • 写経 = 自分でキー入力して写すこと ≠ コピペ
      • 自分が書いたコードをコピペしてから改変するのはOK。
    • 書き方を頭の中に入力する/刷り込むつもりで、時間がかかっても全て手でキー入力してください。
    • IMEの入力補完はOK。
    • 入力間違いによるトライ・アンド・エラーも、学習の中での重要な要素とご理解ください。
  • 紹介する内容は、基本的には分からないものです。一度すべて動作させてから「あー、あんな感じか」とニュアンスを掴んでください。
  • 深く悩んではいけません。

注意

本ワークショップは 60〜120分 を想定しています。そのため、本格的な学習には時間が圧倒的に足りないので、体系的な学習は行いません

本格的に0から思い通りのプログラムが組めるようになるには、自学習もしくは何らかの講座を受講する必要があります。


ターゲット

本ワークショップでは、主に下記の参加者を対象とします。

  • プログラミングを本業としない人
  • プログラミングが苦手、あるいは実用的なプログラムを組んだことが無い人
  • プログラミングの基礎的なことを知らない初心者

中上級者はまったく相手にしていないため、敢えて言及しない事項が沢山あることについてはご了承ください。


プログラミング環境の準備

こちらをごらんください。


前回の復習

次の問題に答えてください。

  • 次のスクリプトを実行すると、何回"Yes"と表示されるか。
review3-1.py
for i in range(5):
    print("Yes")
  • 1のスクリプトで2行目の行頭にスペースがいくつか入力されている。これを「   」と言います。このスペースが空いていることには意味が( ある / ない )

  • 次のスクリプトを実行すると、「    」 と表示される。

review3-3.py
a = (3 * 5 + 1 ) / 2
print(a)

※分からない方は Vol.1 Vol.2 を読み直してください


前回覚えたこと

  • 繰り返し処理
  • 関数の実行方法
  • 四則演算
  • データをダウンロードする方法(POST)
  • Slackへの投稿方法
  • 字下げ(インデント)
  • JSON(という存在)

本日のゴール

定期的&ランダムにSlack へ投稿するスクリプト(ほぼSlack bot)を作成します。

可能であれば、書いた内容については後から正しく理解してください。ただし、完璧に覚える必要はありません。


ハンズオン開始


ハンズオン1


ハンズオン1-0. Slack アカウントとアップロード先の準備

前回と同様に、下記を準備してください。

  • Slack アカウント
  • Slack ワークスペースへのログイン
  • Slack アップロード先URL(Incoming Webhook)

なお、最後のSlack アップロード先URLは、今後「POST先URL」と呼びます。(理由は前回)


ハンズオン1-1. Slack に投稿する(前回と同じ)

c:\scriptフォルダに、次のスクリプトを exp311.py という名前で保存して実行しなさい。

ex311.py
import requests
import json

URL = "[POST先URL]"
MESSAGE = json.dumps({"text": "TEST"})
requests.post(URL, MESSAGE)

もちろん、[POST先URL]は準備したURLに置き換えてください。


ハンズオン1-2. 10秒後に Slack に投稿する

ex11.py をコピーして下記のように書き換えなさい。(自分が書いたコードはコピペOK)

ex312.py
import requests
import json
import time

time.sleep(10)
URL = "[POST先URL]"
MESSAGE = json.dumps({"text": "TEST"})
requests.post(URL, MESSAGE)

その後、exp312.py を保存して、スクリプトを実行しなさい。


ハンズオン1-3. Slack に現在の日時を投稿する

ex11.py をコピーして下記のように書き換えなさい。(自分が書いたコードはコピペOK)

ex313.py
import requests
import json
import datetime

NOW = datetime.datetime.now()
URL = "[POST先URL]"
MESSAGE = json.dumps({"text": str(NOW)})
requests.post(URL, MESSAGE)

その後、exp313.py を保存して、スクリプトを実行しなさい。


解説1


プログラミングのおやくそく(復習)

  • 基本的に上から一行ずつ実行します。
  • プログラミングとは、「プログラムを書く → 実行する → 誤ったところを修正する → 再実行する」を繰り返すのが基本です。
  • なるべく読みやすく、短く書ければ書けるほど良いです。
  • 最初はルールを暗記しないこと。慣れるまでは、後でググれるように練習していくのが近道です。

ハンズオン1-2 解説

実行した ex312.py のうち、ex311.py と異なる点はこちらです。

ex312.py(抜粋)
import time

こちらで時間を扱う time モジュールをインポートしています。

ex312.py(抜粋)
time.sleep(10)

この命令で、10秒間待たせる(sleep)ようにしています。

10秒間待っている間は何も表示されませんが、数えてみるとたしかに10秒間待ってから投稿する仕組みになっています。

このように、待たせる(sleep)させたい場合は、下記を利用します。

sleep書式
time.sleep(秒数)

数秒~数日まで待たせるなど、よく利用する処理の1つです。


ハンズオン1-3 解説

実行した ex313.py のうち、ex311.py と異なる点はこちらです。

ex312.py(抜粋)
import datetime

こちらで時間を扱う datetime モジュールをインポートします。

先程の time モジュールは時間を扱ったツールを中心としたモジュールですが、datetime モジュールは日付や時刻そのものに対して色々な操作をすることを主としたモジュールになります。

ex312.py(抜粋)
NOW = datetime.datetime.now()

こちらの命令で、現在時刻を変数 NOW に格納しています。

ex312.py(抜粋)
MESSAGE = json.dumps({"text": str(NOW)})

こちらの str(NOW) がポイントです。

NOW は時間データが格納されており、人間の目には時刻を現すテキスト(文字列)として認識できます。

しかし、コンピュータは文字列と時刻データを一緒のデータとして扱うことができない特性があります。

このようにデータの特性のことをデータ型(型)と呼びます。

先の NOW に格納された時間データは 時間型、文字列(テキスト)の型は 文字列(String) です。

このデータ型(型)は沢山ありますが、とりあえずは 時間型文字列型(文字列/String)だけを頭の片隅に入れておきましょう。

ex312.py(抜粋)
MESSAGE = json.dumps({"text": str(NOW)})

こちらの記載では、Slack の投稿メッセージを作成していますが、ポイントは str(NOW)です。

本来であれば、NOW で良いはずですが、そのままではエラーとなってしまいます。

これは、NOW が文字列型ではないためです。

お約束として、JSONという書式は いずれも文字列にする必要があるためです。

そのため、str(NOW) とすることで、NOWに格納された値を文字列型に変換できるわけです。

とても面倒くさい「型」ですが、この仕組みは間違ったデータの混入を防ぐ効果もあります。

そのため、徐々に慣れていきましょう。


ハンズオン2


ハンズオン2-1. Slackにランダムなタイミングで投稿する

c:\scriptフォルダに、次のスクリプトを exp321.py という名前で保存して実行しなさい。

ex321.py
import requests
import json
import random
import time

URL = "[POST先URL]"
MESSAGE = json.dumps({"text": "TEST"})
num = random.randint(1, 10)
time.sleep(num)
requests.post(URL, MESSAGE)

もちろん、[POST先URL]は準備したURLに置き換えてください。


ハンズオン2-2. Slackに投稿するスイッチをつける

c:\scriptフォルダに、次のスクリプトを exp322.py という名前で保存して実行しなさい。

ex322.py
import requests
import json

flag = True
URL = "[POST先URL]"
MESSAGE = json.dumps({"text": "TEST"})
if flag is True:
    requests.post(URL, MESSAGE)

もちろん、[POST先URL]は準備したURLに置き換えてください。


ハンズオン2-3. "OK"が含まれていたらSlackに投稿する

c:\scriptフォルダに、次のスクリプトを exp23.py という名前で保存して実行しなさい。

ex323.py
import requests
import json

URL = "[POST先URL]"
MESSAGE = json.dumps({"text": "TEST"})
if "OK" in MESSAGE:
    requests.post(URL, MESSAGE)

MESSAGE = json.dumps({"text": "It is OK."})
if "OK" in MESSAGE:
    requests.post(URL, MESSAGE)

もちろん、[POST先URL]は準備したURLに置き換えてください。


解説2


ハンズオン2-1 解説

実行した ex321.py のうち、確認すべき点はこちらです。

ex321.py(抜粋)
import random

こちらでランダムな数を発生させるためのモジュールを読み込みます。

ex321.py(抜粋)
num = random.randint(1, 10)

ランダムな数を発生させる処理になります。

数をあらわす型にもいくつか種類がありますが、Pythonでよく扱うのは次の2つです。

  • Integer型(略: int): 小数点がつかない整数(1, 2, 3 ...)
  • float型: 小数点をつけた数値 (1.0, 0.1, 15.92 ...)

これらは同じ数字ではありますが、使い分けられるケースがありますので留意しておく必要があります。

これを踏まえて、「ランダムな数値 = ランダムな整数」を発生させる命令として、randintを使用しています。

ちなみに、1~10の整数をランダムに1つだけ発生させるために、random.randint(1, 10) と命令を書いています。

random.randint書式
random.randint(開始数, 終了数)

数式にすると、開始数 <= N <= 終了数 になると理解してください。


ハンズオン2-2 解説

実行した ex322.py のうち、確認すべき点はこちらです。

ex322.py(抜粋)
flag = True

文字列でもなく、数値でもない値を変数に入れています。

こちらの True / False で表現する値は、真偽型(Boolean)と呼びます。

真偽しか扱わない場合に使う, 単純なデータ型です。

ex322.py(抜粋)
if flag is True:
    requests.post(URL, MESSAGE)

こちらでは実行する「条件」を示す命令文になっています。

変数 flag の値が True であったら、下の字下げ(インデント)されている内容が実行されます。

この「条件」を現す命令を「if文」といい、非常によく使います。

IF文書式
if {条件}:
    実行内容

実行内容は、複数あっても構いません。字下げ(インデント)している箇所がすべて同じ対象と見なされます。

IF文例
if a == 1:
    b == 1
    print(b)
    print(a)
    print("bが1ならここまで実行される")

プログラミングの基礎として、必ず出てくるIF文です。

シンプルですが、利用機会も多いですので覚えてしまいましょう。


ハンズオン2-3 解説

実行した ex323.py で確認すべき点はこちらです。

ex323.py(抜粋)
MESSAGE = json.dumps({"text": "TEST"})
if "OK" in MESSAGE:
    requests.post(URL, MESSAGE)

IF文で指定している「if "OK" in MESSAGE:」とは、「変数 MESSAGE の中に 文字列 "OK" を含んでいるならば」という意味合いになります。

このように、変数の中に指定した文字列を含むかどうかを判断させる場合には、in を使います。

in書式
if {含まれていて欲しい文字列} in {確認対象の文字列}:

同じように確認対象の文字列の内容を変更した変数 MESSAGE をIF文で判定しています。

ex323.py(抜粋)
MESSAGE = json.dumps({"text": "It is OK."})
if "OK" in MESSAGE:
    requests.post(URL, MESSAGE)

この場合、完全に一致するわけではなく、変数 MESSAGE の文字列(テキスト)に含まれていれば良い、という判断基準になるのがポイントです。

このように、IF文の条件(条件式と呼ぶ)は多彩なんだと理解してください。


ハンズオン3


ハンズオン3-1. Slackに朝10時以降に投稿する

c:\scriptフォルダに、次のスクリプトを exp331.py という名前で保存して実行しなさい。

ex331.py
import requests
import json
import datetime

NOW = datetime.datetime.now()
AM10 = NOW.replace(hour=10, minute=0, second=0, microsecond=0)

URL = "https://hooks.slack.com/services/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"
MESSAGE = json.dumps({"text": "10時を過ぎました。"})

print("現在は" + str(NOW) + "です。")
print(str(AM10) + "以降なら投稿します。")

if AM10 <= NOW:
    requests.post(URL, MESSAGE)
    print("Slackに投稿しました。")

もちろん、[POST先URL]は準備したURLに置き換えてください。


ハンズオン3-2. Slackに10時~18時なら投稿する

c:\scriptフォルダに、次のスクリプトを exp332.py という名前で保存して実行しなさい。

ex332.py
import requests
import json
import datetime

NOW = datetime.datetime.now()
AM10 = NOW.replace(hour=10, minute=0, second=0, microsecond=0)
PM18 = NOW.replace(hour=18, minute=0, second=0, microsecond=0)

URL = "https://hooks.slack.com/services/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"
MESSAGE = json.dumps({"text": "10時を過ぎました。"})

print("現在は" + str(NOW) + "です。")
print(str(AM10) + "~" + str(PM18) + "なら投稿します。")

if AM10 <= NOW <= PM18:
    requests.post(URL, MESSAGE)
    print("Slackに投稿しました。")

もちろん、[POST先URL]は準備したURLに置き換えてください。


解説3


ハンズオン3-1 解説

実行した ex331.py で確認すべきところはこちらです。

ex331.py
NOW = datetime.datetime.now()

現在時刻を変数 NOW に入れています。

この命令 datetime.datetime.now() は長いですが、定型ですので必要に応じて使いましょう。(理解していれば、コピペで十分です。)

ex331.py
AM10 = NOW.replace(hour=10, minute=0, second=0, microsecond=0)

変数 AM10 に「午前10時」を示す時間データを入れている命令です。

こちらは、変数 NOW のうち、時間を10時に置き換えた時間データを入れています。

変な感じがするかもしれませんが、現在を基準としたデータを扱う方法の1つとして捉えて下さい。

ex331.py
print("現在は" + str(NOW) + "です。")
print(str(AM10) + "以降なら投稿します。")

先に紹介した変数 NOW を文字列に変換しています。

加えて、文字列同士を結合させるには + でつなぎます。

そうすることで、文字列と変数を組み合わせて表示することができます。

ex331.py
if AM10 <= NOW:
    requests.post(URL, MESSAGE)
    print("Slackに投稿しました。")

先に作った変数 AM10 より 現在を現す変数 NOW が大きい、つまり「朝10時を過ぎているならば」というIF文になっているわけです。

条件自体は複雑ではありませんが、条件に使えるようにデータを整えるのに少し手間がかかっていることが理解できますでしょうか。

このように比べるものを整える、型を合わせる、といった作業がプログラミングでは沢山出てきます。


ハンズオン3-2 解説

ここまで解説してきた内容の集大成になります。

ex332.py で確認すべきポイントはこちらです。

ex332.py(抜粋)
AM10 = NOW.replace(hour=10, minute=0, second=0, microsecond=0)
PM18 = NOW.replace(hour=18, minute=0, second=0, microsecond=0)

こちらで変数 AM10 に「朝10時」を示す時間データを、変数 PM18 に「18時」を示す時間データを入れています。

ex332.py(抜粋)
if AM10 <= NOW <= PM18:
    requests.post(URL, MESSAGE)
    print("Slackに投稿しました。")

IF文では、「朝10時 以降、夜6時まで ならば」という条件を示しています。

このように、複数の条件をまとめて設定しても良いのは、Pythonの1つの特徴です。

次の様に記載しても、同じ動きをします。

ex332.py(抜粋)
if AM10 <= NOW and NOW <= PM18:
    省略

省略した方が読みやすくなる場合は、積極的に読みやすい記法を使いましょう。


練習問題

こちらの要件を満たすスクリプトを作って、実行してみましょう。

Q. 毎朝7時にSlackに「おはようございます」と投稿するスクリプト

考慮のポイントは下記です。

  • 毎朝7時以降に、その日は1回だけ実行すること
  • 毎日実行する = プログラムを終了することなく繰り返し実行し続ける

終わりに

今回もプログラミングの基礎的なエッセンスを、いくつも詰め込んだワークショップにしてみました。

特に、プログラミングで重要なキーワードとして「条件式」と「テキストの整形」、「比較演算」を紹介しました。

基礎的な構造は、今回である程度網羅できたはずです。

次回は、これまで学んだ基礎を復習しつつ、もう少し別のプログラムを作ってみることで理解を深めたいと思います。

なお、説明を端折っている部分が沢山ありますが、初心者向けということで玄人は我慢してください。

今後も学習したい方はリクエストをいただければと思います。


公式


Python リファレンスサイト


Python関連書籍


Python 学習サービス

手軽にやれるWebサービス/オンラインスクールを集めました。