Notes

Pythonの基本

  • 今日は、Pythonという新しいプログラミング言語について学びます。C言語よりも新しい言語であるため、単純さだけでなく機能も追加されており、その人気につながっています。
  • PythonのソースコードはCよりもずっと簡単に見えます。実際、「hello, world」を出力するには、以下のように書くだけです。
print("hello, world")
  • C言語とは異なり、print 関数で改行を指定したり、セミコロンを使用して行を終了する必要はありません。
    • このプログラムを作成して実行するには、CS50 IDEを使用し、新しいファイルを上記の行を記入しhello.pyとして保存し、コマンドpython hello.pyを実行します。
  • ユーザーから文字列を取得できます。
answer = get_string("What's your name? ")
print("hello, " + answer)

PythonバージョンのCS50ライブラリcs50get_string関数用にインポートする必要があるため、コードは次のようになります。

from cs50 import get_string

answer = get_string("What's your name? ")
print("hello, " + answer)
  • 型を指定せずにanswer という変数を作成し、+演算子を使用して2つの文字列を結合 (連結) してから出力printに渡すことができます。
  • 書式文字列f"..."の構文を使用して、変数を組み込むことができます。例えば、print(f"hello, {answer}")を作成して、answerの値を中括弧で囲んで文字列に組み込むことができます。
  • counter = 0とするだけで変数を作成できます。値0を割り当てると、型は暗黙的に整数に設定されるため、型を指定する必要はありません。変数を増加させるには、counter = counter + 1またはcounter += 1を使用します。
  • 条件は次のようになります。
if x < y:
    print("x is less than y")
elif x > y:
    print("x is greater than y")
else:
    print("x is equal to y")
  • コードのブロックを示すために中括弧が使用されるCとは異なり、Pythonでは各行のインデントによってネストのレベルが決まります。
    • else ifの代わりに、elifと書きます。
  • ブール式も少し異なります。
while True:
    print("hello, world")
  • Pythonでは、True とFalse の両方が先頭大文字で表記されます。
  • 変数を使ってループを書くことができます。
i = 0
while i < 3:
    print("hello, world")
    i += 1
  • for ループを使用して、リスト内の値ごとに何かを行うこともできます。
for i in [0, 1, 2]:
    print("cough")

  • Pythonのリスト[0, 1, 2]は、Cの配列のようなものです。
    • このfor ループは、変数iに最初の要素0を代入し実行され、次に2番目の要素1を代入し実行されます。
    • 多機能な関数rangeを使うと、for i in range(3)のようにいくつかの値を得ることができます。range(3)は、値0、1、2からなる (3は含まない) 3つの値を持ちます。
    • range()は他のオプションを取ることもでき、異なる値で始まり、リストの要素間で一定の増分を持つリストを作成することもできます。ドキュメントを見ると、例えばrange(0, 101, 2)を使用すると、2ずつ増える0から100までの範囲を取得することができます (2番目の値101は含まれません) 。
    • 変数 iも印刷するには、print(i)と書くだけです。
    • Pythonで同じコードを書くには複数の方法があることが多いので、最も一般的に使用され、受け入れられている方法はPythonicと呼ばれます。
  • Pythonには、多くの組み込みデータ型があります。
    • boolTrue またはFalse
    • float, 実数
    • int, 整数
    • str, 文字列
  • C言語は型が厳密に定義された言語であり、型を指定する必要がありますが、Pythonは型が緩やかに定義されており、型は値によって暗黙的に定義されます。
  • Pythonのその他の型は次のとおりです。
    • range, 番号のリスト
    • list, 変更可能な値のリスト、シーケンス、または変更可能な値
      • リストはC言語の配列に似ていますが、Pythonでは自動的に拡大縮小されます。
    • tuple, タプル、x座標やy座標、経度や緯度などの順序付けられた値の集合
    • dict(dictionary), 辞書、キーと値のペアの集合、ハッシュテーブルのようなもの
    • set, 集合、一意 (重複のない) の値のコレクション
  • Python用CS 50ライブラリには次のものが含まれます。
    • get_float
    • get_int
    • get_string
  • 関数は一度に1つずつインポートすることも、まとめてインポートすることもできます。
from cs50 import get_float
from cs50 import get_int
from cs50 import get_string
import cs50
from cs50 import get_float, get_int, get_string

  • Pythonには、他の人が作成したコードのライブラリーだけでなく、多くの機能が含まれているため、すべての詳細を自分で実装するのではなく、高度な抽象化レベルで問題を解決することができます。
  • 次のようにしてイメージをぼかすことができます。 
from PIL import Image, ImageFilter

before = Image.open("bridge.bmp")
after = before.filter(ImageFilter.BoxBlur(1))
after.save("out.bmp")
  • Pythonでは、importで他のライブラリをインクルードできます。ここでは、PILライブラリからImage とImageFilter の名前をimportします (他の人がこのライブラリを書いて、私たち全員がダウンロードして使えるようにしてくれました)
    • Imageはデータだけでなく、. 構文を使用してアクセスできる関数も併せ持つ構造をしています(Image.openのように)。
    • bridge.bmpという名前の画像を開き、ぼかしフィルタ関数を呼び出して、out.bmpという名前のファイルに保存します。
    • これをblur.pyという名前のファイルに保存した後、python blur.pyで実行できます。
  • 辞書を実装するには、次のようにします。
words = set()

def load(dictionary):
  file = open(dictionary, "r")
  for line in file:
      words.add(line.rstrip())
  file.close()
  return True

def check(word):
    if word.lower() in words:
        return True
    else:
        return False

def size():
    return len(words)

def unload():
    return True
  • 最初に、wordsという新しいセットを作成します。
    • main 関数は必要ありません。Pythonプログラムは上から下へと実行されます。ここでは関数を定義したいので、def load()を使います。load は引数としてdictionaryを受け取り、その戻り値はTrueを返しています。openを使用してファイルを開き、for line in file:を使うだけでファイル内の行を繰り返し処理します。次に、行末の改行を削除し、setのwordsに追加します。line は文字列ですが、.rstrip関数を呼び出すことができます。
    • そうして、check関数内でif word.lower() in wordsを使い確認しています。sizeについては、len を使用してセット内の要素の数をカウントし、最後にunloadについては、Pythonがメモリを管理するため、何もする必要がありません。
  • Pythonでプログラムを実装する方が私たちにとっては簡単ですが、メモリ管理などの汎用的なソリューションでは、より多くの作業を実行する必要があるため、Pythonでのプログラムの実行時間はCでのプログラムよりも遅くなります。
  • さらに、Pythonはインタプリタと呼ばれるプログラムの名前でもあります。インタプリタはソースコードを読み込んで、CPUが理解できるコードに1行ずつ変換します。
  • たとえば、Week 0の擬似コードがスペイン語で、スペイン語が理解できない場合、電話帳で名前を検索する前に、行ごとにゆっくりと英語に翻訳する必要があるでしょう。
1   Recoge guía telefónica
2   Abre a la mitad de guía telefónica
3   Ve la página
4   Si la persona está en la página
5       Llama a la persona
6   Si no, si la persona está antes de mitad de guía telefónica
7       Abre a la mitad de la mitad izquierda de la guía telefónica
8       Regresa a la línea 3
9   Si no, si la persona está después de mitad de guía telefónica
10      Abre a la mitad de la mitad derecha de la guía telefónica
11      Regresa a la línea 3
12  De lo contrario
13      Abandona
  • 私達の目的に応じて、人間がより効率的にプログラムを書く時間と、プログラムの実行時間との間にはトレードオフがあることを考慮する必要があるでしょう。

入力、条件

  • input 関数を使用してユーザーから入力を取得できます。
answer = input("What's your name? ")
print(f"hello, {answer}")
  • ユーザーに2つの整数を入力してもらい、それらを足します。
from cs50 import get_int

# Prompt user for x
x = get_int("x: ")

# Prompt user for y
y = get_int("y: ")

# Perform addition
print(x + y)
  • コメントは、//ではなく#で始まります。
  • inputを呼び出すと、値の文字列が返されます。
# Prompt user for x
x = input("x: ")

# Prompt user for y
y = input("y: ")

# Perform addition
print(x + y)
  • したがって、各値を格納する前に、input をintにキャスト (変換) する必要があります。
# Prompt user for x
x = int(input("x: "))

# Prompt user for y
y = int(input("y: "))

# Perform addition
print(x + y)
  • しかし、ユーザーが番号を入力しなかった場合は、さらにエラーチェックを行う必要があります。そうしないと、プログラムがクラッシュします。このような問題を解決するには、一般的によく使用されるライブラリを使用します。
  • 値を除算します。
# Prompt user for x
x = int(input("x: "))

# Prompt user for y
y = int(input("y: "))

# Perform division
print(x / y)
  • 2つの整数で割ったとしても、浮動小数点の10進数が返されることに注意してください。
  • 条件を示すことができます。
from cs50 import get_int

x = get_int("x: ")
y = get_int("y: ")

if x < y:
    print("x is less than y")
elif x > y:
    print("x is greater than y")
else:
    print("x is equal to y")
  • ライブラリ全体をインポートし、ライブラリ内の関数を構造体のように使用することができます。
import cs50

x = cs50.get_int("x: ")
y = cs50.get_int("y: ")
  • プログラムが2つの異なるライブラリをインポートする必要がある場合、例えばそれぞれがget_int関数を持っている場合、名前が衝突しないように、ライブラリの名前を冠し、異なる名前空間にあるメソッドとして使用する必要があります。
  • 文字列を比較するには、次のように記述します。
from cs50 import get_string

s = get_string("Do you agree? ")

if s == "Y" or s == "y":
    print("Agreed.")
elif s == "N" or s == "n":
    print("Not agreed.")
  • Pythonには文字型 (char) がないので、Yなどの文字を文字列としてチェックします。また、文字列を直接==と比較することもできます。最後に、ブール式では、記号の代わりにorまたはandを使用します。
    • if s.lower() in ["y", "yes"]:で、小文字に変換した後で文字列がリスト内にあるかどうかを調べることもできます。

meow (ニャー)

  • meowの改良版も作れます。
print("meow")
print("meow")
print("meow")
  • main 関数を宣言する必要がないので、同じコード行を3回記述します。
  • 再利用できる関数を定義できます。
for i in range(3):
    meow()

def meow():
    print("meow")
  • しかし、これを実行しようとするとエラーNameError: name 'meow' is not definedが発生します。関数を使用する前に関数を定義する必要があるため、meow の定義を先頭に移動するか、メイン関数を最初に定義することができます。
def main():
    for i in range(3):
        meow()

def meow():
    print("meow")

main()
  • これで、main 関数を実際に呼び出すまでに、meow 関数はすでに定義されています。
  • 関数は入力も取ることができます。
def main():
    meow(3)

def meow(n):
    for i in range(n):
        print("meow")

main()
  • meow 関数はパラメータnを取り、それをrangeに渡します。

get_positive_int

  • 正の整数を取得する関数を定義できます。
from cs50 import get_int

def main():
    i = get_positive_int()
    print(i)

def get_positive_int():
    while True:
        n = get_int("Positive Integer: ")
        if n > 0:
            break
    return n

main()
  • PythonにはCのようなdo-whileループがないので、無限に続くwhile ループで、n > 0になればbreakを使用してループを終了します。最後に、この関数はwhileループの外側の元のインデントレベルでnを返します。
  • Pythonの変数はデフォルトで関数にスコープされることに注意してください。つまり、nはループ内で初期化されますが、関数内から後でアクセスできます。

マリオ

  • 画面にクエスチョンマークを一列に印刷することができます。
for i in range(4):
    print("?", end="")
print()
  • 各ブロックを出力するときは、自動的に改行されないようにするため、キーワード引数とも呼ばれる名前付き引数を、print関数の特殊な引数として渡すことができます。これまでは、関数呼び出し内の位置に基づいてパラメータが設定される位置引数のみを見てきました。
    • ここでは、文字列の最後に何も表示されないようにするために、end=""としています。end はオプション引数でもあり、print は通常では新しい行を追加するため、デフォルト値の\nを渡す必要はありません。このため、print は通常では、新しい行を追加します。
    • 最後に、ループを使用して行を出力した後、他の引数を指定せずにprintを呼び出して新しい行を出力することができます。
  • 文字列を 「乗算」 し、print("?" * 4)で直接出力することもできます。
  • ネストされたループを実装できます。
for i in range(3):
    for j in range(3):
        print("#", end="")
    print()

オーバーフロー、非精度

  • Pythonでは、整数オーバーフローを発生させようとしても実際には動作しません。
i = 1
while True:
    print(i)
    i *= 2
  • 整数が特定のバイト数に固定されているC言語とは異なり、Pythonは自動的により多くのメモリを使用して数値を格納するため、出力される数値はどんどん大きくなります。
  • 浮動小数点数の精度は存在しますが、ライブラリによって必要十分な精度で小数を表現することができます。

リスト、文字列

  • リストを作りましょう。
scores = [72, 73, 33]

print("Average: " + str(sum(scores) / len(scores)))
  • sum (Pythonに組み込まれた関数) を使用してリスト内の値を合計し、それをスコアの数で割ります。len関数を使用してリストの長さを取得できます。次に、連結して出力する前に、floatを文字列にキャストします。
    • 同じ結果を得るために、書式付き文字列に式全体を追加することもできます。
print(f"Average: {sum(scores) / len(scores)}")
  • 以下を使用してリストにアイテムを追加できます。
from cs50 import get_int

scores = []
for i in range(3):
    scores.append(get_int("Score: "))
...
  • 文字列内の各文字を繰り返すことができます。
from cs50 import get_string

s = get_string("Before:  ")
print("After: ", end="")
for c in s:
    print(c.upper(), end="")
print()
  • Pythonは文字列中の各文字をfor c in sだけで繰り返します。
  • 文字列を大文字にするには、s.upper()を呼び出すだけでよく、各文字をループさせる必要はありません。  

コマンドライン引数、終了コード

  • 次のコマンドライン引数を使用できます。
from sys import argv

if len(argv) == 2:
    print(f"hello, {argv[1]}")
else:
    print("hello, world")
  • Pythonに組み込まれているシステムモジュール sysからargvをインポートします。
    • argvはリストなので、argv[1]で2番目の項目を取得できます。したがって、コマンドpython argv.py Davidで引数を追加すると、hello, Davidが出力されます。
    • Cと同様、argv[0]argv.pyのようなプログラムの名前です。
  • また、Pythonにリストを繰り返し処理させることもできます。
from sys import argv

for arg in argv:
    print(arg)
  • プログラムの終了時に終了コードを返すこともできます。
import sys

if len(sys.argv) != 2:
    print("missing command-line argument")
    sys.exit(1)
print(f"hello, {sys.argv[1]}")
sys.exit(0)
  • 複数のコンポーネントを使用しているため、sysモジュール全体をインポートします。これでsys.argvsys.exit()を使ってプログラムを特定のコードで終了できます。

アルゴリズム

  • リスト内の各要素をチェックするだけで、線形探索を実装できます。
import sys

numbers = [4, 6, 8, 2, 7, 5, 0]

if 0 in numbers:
    print("Found")
    sys.exit(0)

print("Not found")
sys.exit(1)
  • if 0 in numbersで、リストをチェックするようPythonに指示しています。
  • 文字列のリストも次のように検索できます。
names = ["Bill", "Charlie", "Fred", "George", "Ginny", "Percy", "Ron"]

if "Ron" in names:
    print("Found")
else:
    print("Not found")
  • 辞書 (キーと値のペアのセット) がある場合、特定のキーをチェックし、そのキーに対して格納されている値を調べることもできます。
from cs50 import get_string

people = {
    "Brian": "+1-617-495-1000",
    "David": "+1-949-468-2750"
}

name = get_string("Name: ")
if name in people:
    print(f"Number: {people[name]}")
  • まず辞書peopleを宣言します。ここで、キーは保存したい名前の文字列で、各キーに関連付けたい値は対応する電話番号の文字列です。
    • そして、if name in people:を使って辞書のキーから名前nameを検索します。キーが存在する場合は、ブラケット表記の値people[name]を取得することができます。これは、Cで配列にインデックスを付ける場合とよく似ていますが、ここでは整数の代わりに文字列を使用します。
    • 辞書は、集合と同様に、ハッシュテーブルのようなデータ構造を使ってPythonで実装されているのが普通なので、ほぼ一定の時間検索を行うことができます。繰り返しになりますが、内部で何が起こるかを正確に制御することができなくなるというトレードオフがあります。たとえば、ハッシュ関数を選択できるというメリットと、自分で行う作業が減るというメリットのトレードオフです。
  • 2つの変数の入れ替えは、単に両方の値を同時に割り当てることによって行うこともできます。
x = 1
y = 2

print(f"x is {x}, y is {y}")
x, y = y, x
print(f"x is {x}, y is {y}")
  • Pythonではポインタにアクセスできなくなっていて、メモリでの操作ミスから守ってくれています。

ファイル

  • CSVファイルを開きます。
import csv

from cs50 import get_string

file = open("phonebook.csv", "a")

name = get_string("Name: ")
number = get_string("Number: ")

writer = csv.writer(file)
writer.writerow([name, number])

file.close()
  • PythonにはCSVファイルを扱うためのcsvライブラリもあります。ファイルに追記するためにオープンした後、fileからwriterを作成するためにcsv.writerを呼び出すことができます。これによりwriter.writerowのような関数が使えるようになり、行としてリストを書き込むことができます。
  • with キーワードを使用すると、完了後にファイルが閉じられます。
...
with open("phonebook.csv", "a") as file:
    writer = csv.writer(file)
    writer.writerow((name, number))
  • 別のCSVファイルを開き、値が表示される回数を集計します。
import csv

houses = {
    "Gryffindor": 0,
    "Hufflepuff": 0,
    "Ravenclaw": 0,
    "Slytherin": 0
}

with open("Sorting Hat (Responses) - Form Responses 1.csv", "r") as file:
    reader = csv.reader(file)
    next(reader)
    for row in reader:
        house = row[1]
        houses[house] += 1

for house in houses:
    print(f"{house}: {houses[house]}")
  • csvライブラリからreader関数を使用し、next(reader)でヘッダ行をスキップし、残りの各行(ヘッダ行の次の行から)を繰り返します。
    • 各行の2番目の項目であるrow[1]は、houseの文字列です。この文字列を使用して、housesに格納されているそのキーの値にアクセスし、またキーを追加できます。
    • 最後に、各houseのカウントを印刷します。

その他のライブラリ

  • 私たちのMacやPCで、Pythonをインストールした後にターミナルを開き、別のライブラリを使ってテキストを音声に変換することができます。
import pyttsx3

engine = pyttsx3.init()
engine.say("hello, world")
engine.runAndWait()
  • ドキュメントを読むことで、ライブラリの初期化方法や文字列の発音のさせ方を知ることが出来ます。
    • 書式文字列をengine.say(f"hello, {name}") に渡して入力を伝えることもできます。
  • 別のライブラリであるface_recognitionを使用して、イメージ内の顔を検索できます。
# Find faces in picture
#https://github.com/ageitgey/face_recognition/blob/master/examples/find_faces_in_picture.py

from PIL import Image
import face_recognition

# Load the jpg file into a numpy array
image = face_recognition.load_image_file("office.jpg")

# Find all the faces in the image using the default HOG-based model.
# This method is fairly accurate, but not as accurate as the CNN model and not GPU accelerated.
# See also: find_faces_in_picture_cnn.py
face_locations = face_recognition.face_locations(image)

for face_location in face_locations:

    # Print the location of each face in this image
    top, right, bottom, left = face_location

    # You can access the actual face itself like this:
    face_image = image[top:bottom, left:right]
    pil_image = Image.fromarray(face_image)
    pil_image.show()
  • recognize.pyを使えば、特定の顔にマッチするものを見つけるプログラムを書くことができます。
  • 別のライブラリを使用して、QRコードまたは2次元バーコードを作成できます。
import os
import qrcode

img = qrcode.make("https://youtu.be/oHg5SJYRHA0")
img.save("qr.png", "PNG")
os.system("open qr.png")
  • マイクからの音声入力を認識できます。
import speech_recognition

# Obtain audio from the microphone
recognizer = speech_recognition.Recognizer()
with speech_recognition.Microphone() as source:
    print("Say something:")
    audio = recognizer.listen(source)

# Recognize speech using Google Speech Recognition
print("You said:")
print(recognizer.recognize_google(audio))
  • マイクを使った音声入力を行うライブラリのドキュメントに従って、音声をテキストに変換します。
  • 基本的な応答を行う拡張機能を追加することもできます。
...
words = recognizer.recognize_google(audio)

# Respond to speech
if "hello" in words:
    print("Hello to you too!")
elif "how are you" in words:
    print("I am well, thanks!")
elif "goodbye" in words:
    print("Goodbye to you too!")
else:
    print("Huh?")
  • 最後に、さらに洗練された別のプログラムを使用して、ディープフェイク、つまり本物のように見えるがコンピュータで生成されたさまざまなパーソナリティのビデオを生成できます。
  • オンラインで自由に利用できるこれらのライブラリを利用することで、独自のアプリケーションに高度な機能を簡単に追加できます。