このスライドの使い方

  • 画面下の「▶」で再生開始、「⏸」で一時停止

  • 画面右下の「>」で次頁へ、「<」で前頁へ

  • 青字下線の部分は、まとめプリントの穴埋め

  • 作業」のところでは、ファイルをダウンロードしてコンパイル・実行

プログラミング言語 Python

Python の特徴

1990 年発表、 Guido van Rossum(蘭)による

  • マルチパラダイム
    (手続き型 + オブジェクト指向 + 関数型
  • 動的型付け

のプログラミング言語である

Python の特徴(続き)

ライブラリーが豊富で

  • Web アプリケーション
  • 機械学習などデータサイエンス分野

などで広く用いられる

2010 年代後半から急速に人気が高まってきている

Python に関係する Web ページ

(すべて https:// を省略している。)
www.python.orgPython Software Foundation
www.python.jppython.jp
www.djangoproject.comDjango
jupyter.orgJupyter Notebook

Python のインストール

Python を実行できる Web ページも紹介している

Python の実行(対話的環境)

python というコマンドで起動する

  • プロンプト(通常、>>>)のあとに式を入力すれば、その値を出力する
    
    >>> 1 + 1
    2
    
  • quit() または exit() と入力すれ ば終了する

Python の実行(ファイル)

python ファイル名 というコマンドで、ファイルに保存したプログラムを実行できる


$ python factorial.py

(「$」はプロンプト)

他の Python 実行環境

統合開発環境 (IDE)

  • IDLEidle というコマンドで起動する)
  • PyCharm
  • Spyder

や Jupyter Notebook が有名

代入と関数定義

変数と代入

変数は「=」の左辺に書き、右辺の値を代入する


>>> x = 2  
>>> x * 3
6

宣言は特になく、変数に初めて代入したときに用意される
⇐ 綴りの間違いには気を付ける必要がある

関数定義

関数はキーワード def により定義できる


>>> def fact(n):
...     if n == 0:
...         return 1
...     else:
...         return n * fact(n - 1)
...
>>> fact(10)
3628800      
... ⋯ 第 2 プロンプト

関数定義(続き)

関数定義は、

  • キーワード def
  • 関数名(この例では fact
  • 丸括弧「(」〜「)」の中の
    • 仮引数のコンマ「,」区切りの並び
      (この例では n のみ)
  • コロン「:

で始まる。改行後に関数の本体を記述する

関数定義(続き)

関数の本体はインデント(字下げ)する

  • つまり def の位置よりも数文字分下げる
    (この例では 4 文字)
  • インデントしている限り、関数の本体が続いていると見なされる

return 文は(セミコロンがないこと以外は)C と同じ

注意!

Python はインデンテーションが意味を持つ

(一方、C や Java はどのようにインデントしてもプログラム の意味は変わらない

インポート

ファイルに関数などを書いて import 文で読み込む

ファイル factorial.py


def fact(n):
    if n == 0:
        return 1
    else:
        return n * fact(n - 1)

Python ソースファイルには拡張子.py をつける

インポート(続き)


>>> from factorial import *
>>> fact(20)
2432902008176640000   

Ideone で実行 Rextester で実行 JDoodle で実行

  • fromimport *
    〜 というモジュールか定義を読み込む
  • モジュール
    • Python の定義の入ったファイル
    • モジュール名はファイル名 − .py

リテラル

数値リテラル

  • 整数や浮動小数点数のリテラルの書き方は他の言語と大きな違いはない
  • 接尾辞 j をつけることで虚数を表せる

    
    >>> (1 + 1j) / (1 - 2j) 
    (-0.2+0.6j)
    

文字列リテラル

  • 二重引用符「" または一重引用符「' で囲まれた文字列
  • 文字リテラルは存在しない
    — 一重引用符/二重引用符どちらも意味は変わらない
  • 
    >>> "hello"
    'hello'
    >>> 'world'
    'world'
    

三重クオート文字列

  • 三連続の二重引用符"""または一重引用符 '''で囲む
  • 改行や一重引用符・二重引用符を含む文字列を表せる

>>> """Mike said "Hello!"
... and Anne said "Good Bye!"
... """
'Mike said "Hello!"\nand Anne said "Good Bye!"\n'

フォーマット済み文字列リテラル

  • 引用符の前に接頭辞 f または F をつける
  • 波括弧「{」〜「}」に囲まれた部分が式として評価され、文字列中に埋め込まれる

>>> x = 13
>>> f"The factorial of {x} is {fact(x)}."
'The factorial of 13 is 6227020800.'

問 P.3.1

f 文字列のなかに波括弧(「{」または「}」)を 含めたいときはどうすれば良いか調べよ

演算子と組み込み関数

算術演算子

  • 算術演算子は C や Java の演算子と似ている
  • /」は通常の(小数になりうる)除算になる
  • 整数としての商を求めるには「//」を用いる
  • 余りを求める演算子は「%」である

>>> 1 / 3 
0.3333333333333333
>>> 17 // 6
2
>>> 17 % 6
5

算術演算子(続き)

**」は累乗を求める演算子である


>>> 2 ** 10
1024
>>> 2 ** 0.5
1.4142135623730951

print 関数

  • 画面に出力する
  • いくつかの引数をコンマで区切って与えると、それらを順に出力する

>>> y = 23
>>> print(x, "+", y, "=", x + y)
13 + 23 = 36

print 関数(続き)

  • 最後に sep=〜 と指定すると、区切り文字を〜に変えることができる
  • 区切り文字を何も指定しないと先の例のように空白文字が区切りに使われる

>>> print(x, "+", y, "=", x + y, sep=',')
13,+,23,=,36

キーワード引数 ⋯ キーワード=式のカタチの引数

input 関数

  • キーボードから文字列を読みこむ
  • int 関数(整数への変換) や float 関数(浮動小数点数への変換)と組み合わせる

input 関数(例)

ファイル名 temp.py


x   = float(input('x を入力してください: '))
y   = float(input('y を入力してください: '))
z   = int(input('z を入力してください: '))
age = int(input('年齢を入力してください: '))

Ideone で実行 Rextester で実行 JDoodle で実行

制御構造

if 文

  • 条件分岐を表す
  • if というキーワード、条件式、コロン 「:」で始まり、改行後に条件が成り立つときに実行する文を並べる

if x < 0:
    print('x は負の数です。')
    print('正の数や 0 ではありません。')

if 文(続き)

条件が成り立つときに実行する文はインデント(字下げ)する、つまり

  • if の位置よりも数文字(この例では 4 文字)分開始を下げる
  • ここに複数の文を並べることもできる
  • 同じ字下げ幅である限りは、条件が成り立つときには実行する

else 節

条件が成り立たないときに実行する文は、キーワード else、 コロン「:」のあとに改行して書く


if y < 0:
    print('y は負の数です。')
    print('正の数や 0 ではありません。')
else:
    print('y は正の数または 0 です。')
    print('負の数ではありません。')

elif 節

ifelse の間に
elif とい うキーワード、条件式、コロン「:」、改行、インデントした文の並び、というカタチをはさめる

  • 上から順に条件式を評価し、真のとき対応する文の並びを実行する

if z <= 0:
    print('z は負の数か 0 です。')
elif z < 10:
    print('z は一桁の正の数です。') 
elif z < 100:
    print('z は二桁の正の数です。') 
else:
    print('z は三桁以上の正の数です。') 

論理演算子

条件式は and(〜かつ〜)、or (〜または〜)、not(〜でない)などの論理演算子で組み合わせる ことができる


if 13 <= age and age <= 19:
    print('あなたはティーンエイジャーです。')

論理演算子(続き)

Python では比較演算子は連ねることができる(C や Java と異なる)
→ 先の例は次のように書くこともできる


# x < y < z は x < y and y < z と同じ。
# ただし、前者では y は一度しか評価されない。
if 13 <= age <= 19:
    print('あなたはティーンエイジャーです。')

#」から行末まではコメントである

for 文

  • 決まった回数の繰り返しを実現する
  • キーワード for、変数、キーワード in、式、コロン「:」 というカタチで使われる

ファイル名 temp2.py


for i in range(5):
    print('Hello')
    print('  ', i, '回目')

Ideone で実行 Rextester で実行 JDoodle で実行

range 関数

range(n) ⋯ 0 から n - 1 までの整 数の列を返す

先程の例は、変数 i に 0, 1, …, 4 が順に代入される

Hello
   0 回目
Hello
   1 回目
Hello
   2 回目
Hello
   3 回目
Hello
   4 回目

range 関数(続き)

range 関数は次のようなカタチでも使われる

range(n)\(0\), \(1\), ⋯, \(n - 1\) を返す。
range(m, n)\(m\)\(m + 1\), ⋯, \(n - 1\) を返す。
range(m, n, s)\(m\)\(m + s\), ⋯, \(m + k \cdot s\) を返す。

ただし、\(k\)\(m + k \cdot s\)\(n\) 未満となるような最大の \(k\)

while 文

  • 繰り返しを表す
  • キーワード while、条件式、コロン「:」、改行後に繰り返す文をインデントして並べて書く

n = 1000
while n > 0:
    print(n, end=', ')
    n = n // 2   # n //= 2 と書いてもよい
print()          # 改行のみ出力する

Ideone で実行 Rextester で実行 JDoodle で実行

print 関数(end キーワード引数)

print 関数にend= とキーワード引数を指定すると最後に出力 する文字を変えることができる
(何も指定しないと改行文字を最後に出力する)

先の例を実行すると、次のように出力する

1000, 500, 250, 125, 62, 31, 15, 7, 3, 1, 

※ Python に do〜while 文に相当する構文はない

リスト (list)

リスト

  • 単純だが有用性の高いデータ型
  • 関数型言語などで多用
  • 配列と同様に同種のデータを集めたものだが
    • 要素の追加・削除が可能
    • 配列のような各要素への高速アクセスは不可

リストリテラル

  • 角括弧[])で囲み
  • 各要素をコンマ「,」で区切って並べる
  • [] ⋯ 空リスト
  • [2, 3, 5] ⋯ 2, 3, 5 からなるリスト

リストは「+」演算子や「+=」演算子で連接できる


>>> w = [1,3] + [0]
>>> w += [6,2,3]
>>> w
[1, 3, 0, 6, 2, 3]

リスト内包表記 (list comprehension)

数学の集合の表記に似た糖衣構文 (syntax sugar)


>>> [x * y for x in range(1, 5) for y in range(5, 8)]
[5, 6, 7, 10, 12, 14, 15, 18, 21, 20, 24, 28]
>>> [x * x for x in range(1, 11) if x % 2 == 1]
[1, 9, 25, 49, 81]

リスト内包表記 (続き)

  • 角括弧([])のなかに最初に式を一つ書き
  • そのあとに、
    • for 変数 in 式」というカタチか
    • if 式」というカタチを
    並べたもの

その値は

  • for 変数 in 式」という繰り返しの中で
  • if 式」という条件が成り立つときの

最初の式の値を順に並べたもの

Q P.6.1

次のリスト内包表記の値は何か?

[x * y  for x in [1,2] for y in [3,5,7]] 

ヒント:


for x in [1,2]:
    for y in [3,5,7]:
        print(x * y)  

の出力を並べたものと同じになる

タプル(tuple, 組)

タプル

  • 要素を「,」(コンマ)で区切って並べ、丸括弧「(」と「)」で囲んで表す
    • ただし、丸括弧を省略できる場合がある
  • 並べた要素の種類が同一である必要はない
    (リストは、通常各要素は同種からなる)

タプル(続き)

関数の戻り値に使えるし、代入文の左辺に書ける

ファイル名 temp3.py


def sort2(m, n):
    if m > n:
        return (m, n)
    else:
        return (n, m) 

i1 = int(input('整数 1 を入力してください: '))
i2 = int(input('整数 2 を入力してください: '))

(j1, j2) = sort2(i1, i2)
print('大きいほうは', j1, '小さいほうは', j2, 'です。')

Ideone で実行 Rextester で実行 JDoodle で実行

タプル(続き)

特に次のように書くと、2 つの変数の内容を入れ替えることができる


y, x = x, y

(この例ではタプルのまわりの丸括弧が省略されている)

Q P.7.1

次のリスト内包表記の値は何か?


[(x, y) for x in [1,4,7] 
        for y in [2,5,8] if x < y]

ヒント:


for x in [1,4,7]:
    for y in [2,5,8]:
        if x < y:
            print((x, y))

問 P.7.2

3 つの実数 a, b, c を受け取り、二次方程式 \(a x^2 + b x + c = 0\) の 2 つ の解を組として返す関数 quadratic を定義せよ

標準ライブラリー関数 zip

  • 2 つ以上のイテラブルの同じ位置の要素をタプルにしたもののイテラブルを返す
  • イテラブルの長さが異なる場合は、短いほうにあわせる

イテラブル (iterable) ⋯ いくつかの要素を列挙したデータ
(リストもイテラブルの一種)


>>> list(zip([1,3,5,7,11], [2,4,6,10]))
[(1, 2), (3, 4), (5, 6), (7, 10)]

一般にイテラブルを表示するためには list 関数でリストに変換する必要が ある

高階関数とラムダ式

高階関数

関数を引数に取る(あるいは戻り値とする) 関数

リストに対しては、いくつかの高階関数が標準ライブラリーに用意されている

標準ライブラリー関数 map

リストの要素に一斉に関数を適用し、その戻り値のリストを返す関数 (正確にはイテラブルを受け取って、イテラブルを返す関数)

map 関数(続き)

この関数は次のように使用する


>>> list(map(chr, [97, 98, 99, 100]))
['a', 'b', 'c', 'd']
>>> def twice(n):
...     return 2 * n
>>> list(map(twice, [97, 98, 99]))
[194, 196, 198]

chr ⋯ 文字コードに対し対応する一文字からなる文字列を返す関数

ラムダ式

名前をつけずに関数を表現する記法
(ラムダという名前は、かつて数学の一分野で、この目的のためにギリシャ文字の 「λ」が使われたことに由来する)

例: lambda x: 2 * xtwice と同等の関数


def twice(x):
    return 2 * x

ラムダ式(続き)

キーワード lambda とコロン「:」の間に仮引数のコンマ区切りの並びを、 コロンの右側に戻り値の式を書く

使用例:


>>> list(map(lambda x: x * x, [2, 3, 5]))
[4, 9, 25]

標準ライブラリー関数 filter

リストの要素の中で、与えられた関数の値を真にする要素だけのリストを返す


>>> list(filter(lambda x: x % 2 == 0, [2, 3, 5, 8]))
[2, 8]

ジェネレーター(generator)

ジェネレーター関数(generator function)

コルーチン (coroutine) の一種を提供する

コルーチン ⋯ 2 つ以上のプログラムの実行単位が、 交互に制御を受け渡しながら実行されていく方式

  • 通常の関数(サブルーチン)はリターンすると、次に実行するときはもう一度最初から
  • コルーチンは次に実行するときに前回リターンした地点の続きから

ジェネレーター (続き)

ファイル名 fib.py


def gfib(n): 
    a = 1
    b = 1
    while a < n:
        yield a 
        a, b = b, a + b

Python のジェネレーター関数では yield というキーワード を使って値を生成する

ジェネレーター (続き)

  • ジェネレーター関数を呼び出すと、すぐに関数内部のコードが実行されるので はなく、一旦、ジェネレーターイテレーター (generator iterator) が作られ て返される
  • このジェネレーターイテレーターを引数として next 関数を呼び出すと、ジェネレーター関数内部のコー ドが実行され、yield された値を next の戻り値として返す
  • さらに next 関数を呼び出すと先の yield の続きから実行が再開され、やはり、 次の yield された値を返す

ジェネレーター (実行例)


gen = gfib(100)
print(next(gen))        # 1 を出力する
print(next(gen))        # 1 を出力する
print(next(gen))        # 2 を出力する
print(next(gen))        # 3 を出力する
print(next(gen))        # 5 を出力する
print(next(gen))        # 8 を出力する

ジェネレーター (続き)

ジェネレーターイテレーターは for 文の in の次の式でも使える。 このとき for 文は

  • ジェネレーターイテレーターを next 関数に渡し、返される値を順に変数に代入してループする
  • ジェネレーター関数の中のコードの実行が return 文によりリターンするか、関数を抜けるとループを終了する

for v in gfib(20):
    print(v, end=' ')

Ideone で実行 Rextester で実行 JDoodle で実行

この部分は「1 1 2 3 5 8 13 」と出力する

ジェネレーター (続き)

ジェネレーターは必ずしも有限個の要素で終わる必要はない — 例:


def ifib(): 
    a = 1
    b = 1
    while True:
        yield a 
        a, b = b, a + b

ジェネレーター (続き)

次のようにすると、


for i, v in zip(range(15), ifib()):
    print(v, end=' ')
print()

Ideone で実行 Rextester で実行 JDoodle で実行

この部分は「1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 」と出力する

問 P.9.1

整数 \(n\) を引数として受け取り、最初は \(n\) を yield し、以降、

  1. 直前に yield した値が偶数ならば \(n / 2\) を yield する、
  2. 直前に yield した値が奇数ならば \(3 n + 1\) を yield する、

という処理を繰り返すジェネレーター関数 hailstone を定義せよ

例: エラトステネスの篩(ふるい)

素数列を生成するプログラムを例として挙げる


def ifrom(n):
    while True:
        yield n
        n += 1

def sieve(n, xs):
    for i in xs:
        if i % n != 0:
            yield i

def primes():
    xs = ifrom(2)
    while True:
        n = next(xs)
        yield n
        xs = sieve(n, xs)

エラトステネスの篩(続き)

ifrom(2) =
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, …
sieve(2, ) =
[3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, …
sieve(3, ) =
[5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49, 53, …
sieve(5, ) =
[7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 49, 53, 59, 61, 67, …
sieve(7, ) =
[11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, …
sieve(11, ) =
[13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, …
   ⋮

エラトステネスの篩(続き)

この primes() は無限に素数を生成するので、例えば range のように有限のものと zip する


for i, p in zip(range(20), primes()):
    print(p, end=' ')

Ideone で実行 Rextester で実行 JDoodle で実行

この for 文は、

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 

と 20 個の素数を出力する

第 P 章・終