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, 辞書、キーと値のペアの集合、ハッシュテーブルのようなもの
    • 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を受け取り、その戻り値は暗黙的に指定されます。openを使用してファイルを開き、for line in file:を使用してファイル内の行を繰り返し処理します。次に、行末の改行を削除し、設定した単語wordsを追加します。line は文字列ですが、.rstrip関数を呼び出すことができます。
    • そうして、checkif 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 はオプション引数でもあり、デフォルト値\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は自動的により多くのメモリを使用して数値を格納するため、出力される数値はどんどん大きくなります。
  • 浮動小数点精度はまだ存在しますが、必要なだけのビット数で10進数を表現できるライブラリによって防ぐことができます。

リスト、文字列

  • リストを作りましょう。
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ライブラリもあるので、ファイルを追加するためにオープンした後、csv.writerを呼び出してファイルから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")
sengine.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:")
sprint(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?")
  • 最後に、さらに洗練された別のプログラムを使用して、ディープフェイク、つまり本物のように見えるがコンピュータで生成されたさまざまなパーソナリティのビデオを生成できます。
  • オンラインで自由に利用できるこれらのライブラリを利用することで、独自のアプリケーションに高度な機能を簡単に追加できます。