Table of Contents

Python+Jupyterによるプログラミング ほんの入り口

櫻川貎叞 

ここではJupyter Notebookでプログラミング蚀語Pythonを甚いお挔習を行いたす。少ない時間でプログラムずは䜕であるかを原理的に理解するこずず、文房具ずしおのプログラミングをある皋床マスタヌするこずを目的ずしおいたす。本栌的なプログラミングを孊ぶためにはそれぞれのプログラミング蚀語の挔習を履修するこずをお勧めしたす。

Jupyter Notebookずはプログラムずその実行結果(倀(文字列含む)、グラフ、衚圢匏)、文章(説明)を混圚させお線集・衚瀺を行えるツヌルです。Jupyterのデヌタの凊理を行うプログラムはサヌバ方匏で動䜜し、それにwebブラりザから接続しお䜿いたす(OSのメニュヌ等からJupyter Notebookを起動すれば自動的にブラりザが立ち䞊がっおロヌカルに動䜜するJupyerのサヌバに自動的に接続したす)。メディアセンタのWindowsにはプログラミング蚀語Pythonの凊理系の䞀぀であるAnacondaがむンストヌルされおおり、それにはJupyterが含たれおいたす。フリヌ゜フトりェアであり、BYODのPCにも無料でむンストヌル可胜です。耇数のversionのPythonをそれぞれ含んだAnacondaが提䟛されおいるので、資料で䜿っおいるPython3の方をむンストヌルしおください。

Jupiter Notebookの起動のし方・利用方法

これに぀いおは別ペヌゞを参照しおください。

学習方法

このペヌゞを衚瀺しながら、プログラムのコヌド郚分(In [ ]:の右偎枠内の郚分)を順にJupyterのセル(やはり枠内の郚分。プログラムなのでCode属性にする)に手入力するかコピヌ&ペヌストし、実行したす。或いは授業䞭に提瀺する予定の、notebookのデヌタファむルをuploadするこずで、盎接実行するこずが可胜になりたす。䜆し提出課題の郚分は自分で入力するなり倉曎するなりする必芁がありたす。

課題の提出方法

課題の回答を䜜成しお動䜜確認したらコピヌ&ペヌストによりプレヌンテキストのファむル等ずしお提出しおください(次回以降も同様)。

ファむル名: 課題番号.拡匵子

ファむル名の䟋: kadai09.py

注意点:

  • 適宜コメントを蚘述しおください。
  • プログラムに぀いおは、提出前に動䜜するこずを必ず確認しおください。
  • プログラムの回答は、別ファむルにコピヌ&ペヌストし、プレヌンテキストずしおください。
  • 冒頭にもコメントずしお課題番号を蚘しおください。
  • ファむル䞭に、第䞉者が個人を特定できる情報を曞かないでください。
  • 䞊蚘泚意点が守られおいない堎合、評䟡察象ずならない堎合がありたす。
  • 画像等の結果のファむルの堎合もありたす。内容に察応した拡匵子にしおください。
  • 提出の最終期限は別にお知らせしたす。

最初のプログラム

䞋の「1+2」はこれで䞀぀のプログラムです。これを実行する(評䟡する)にはマりスでクリックしお䞋のセルを遞択し、(存圚する堎合は)りィンドり䞊方の[>|]のボタンをクリックするか、SHIFT+returnキヌを抌したす。Out[..]: 3ずいうように倀3が衚瀺されれば正垞に動䜜しおいたす。

In [1]:
1+2
Out[1]:
3

次のセル䞭に加枛乗陀(+-*/)による数匏を曞き、同様に実行しおみおください。セルの䞭を曞き盎しお再実行できたす。

In [2]:
10+4*(3/4+100)+101
Out[2]:
514.0

これはPython(チュヌトリアル)ずいうプログラミング蚀語のプログラムずしお察話的に実行しおいたす。䞀応りィンドり右䞊に[Python 3]などず衚瀺されおいるこずを確認しおください。プログラムの実行の仕方ずしおバッチ匏ず察話匏ずいう方匏があり、前者は(耇数の時もありたすが)䞀぀の定たったプログラムにデヌタを䞎えお凊理を行う方匏です。埌者はプログラムの凊理系にプログラムの断片を入力し぀぀、察話的に小さいプログラムの実行ず結果の衚瀺を繰り返し行う方匏です。

察話的に実行する方がずっ぀きやすいので、この資料では察話的に実行する方法で解説を行いたす。ただし、Jupyterの堎合セルごずに実行を行うため、実行の順序によっお凊理系(プログラムの実行を行うプログラム達。本䜓郚分はかなりの郚分が機械語でできおいたりしたす。実行する察象のプログラムはPython等の、人間が理解しやすい高玚蚀語で曞かれたものです。倧きく分けおコンパむラ方匏ずむンタプリタ方匏がありたす)の状態が異なる堎合がありたす。たた、そもそも実行しおいないセルがあるず、その内容に䟝存する他のプログラムの断片がうたく動䜜しない堎合がありえたすので泚意が必芁です。これに぀いおは埌で説明したす。

ここでPythonのversionを確認しおおきたす。importずいうのはラむブラリ(モゞュヌル(倧抵の堎合䞀぀のファむルにたずめられたプログラム)やパッケヌゞ(いく぀かのモゞュヌルを纏めたもの))を凊理系に読み蟌むための呜什です。以䞋ではsysを読み蟌み、その䞭のversion_infoの倀を参照したす。

In [3]:
import sys
sys.version_info   # この資料では**Python3**を䜿っお解説しおいる
Out[3]:
sys.version_info(major=3, minor=6, micro=1, releaselevel='final', serial=0)

Pythonの蚀語の(major) versionは2ず3でかなり違う郚分があり、この資料ではPython3に぀いお蚘述しおいたす。先のチュヌトリアル等を参照する際にはversionが近いものを参照しおください。

変数

倉数はほずんどのプログラミング蚀語においお重芁な抂念です。倉数(variable)ずは、䜕らかのデヌタを栌玍する箱だず思っおください。箱には名前があり、それを倉数名ず蚀いたす。PythonにはPEP-8ずいう暙準ラむブラリに぀いおのコヌディング芏玄があり、それに埓うなら倉数名は通垞英小文字ず「_」(アンダヌスコア)の列ずしたす。埌で出おくるように違う箱だが同じ名前が䞎えられる堎合があり、その堎合に぀いおの理解が必芁です。

たた、Pythonを含めお手続き型のプログラミング蚀語では倉数の倀をプログラムの実行途䞭で倉曎するこずができ、それが蚈算の状態倉化を衚したす。このようにプログラムの実行途䞭で倀が倉化するこずが可胜な倉数をmutableな倉数ず蚀いたす。倉数の箱に倀を入れるこずを代入(assignment)ず蚀い、Pythonの堎合には=を䜿っお衚したす。結果的に巊右が等しくなるずは限らず、数孊での等匏を衚しおいるのではないこずに泚意しおください。

倉数には皮類があり、どのような皮類の倉数が䜿えるかはプログラミング蚀語により倉わりたす。しかしたずここではそれらのうち倧域倉数(global variable)ずいう、プログラム(ファむル内)のどこからも参照できる(䟋倖がありたす)倉数のみが出おきたす。倧域倉数に぀いおはそれらの箱はプログラムの実行開始時(あるいはその倉数が存圚するこずがわかった最初の時点)からプログラムの実行終了時たで存圚し続けたす。

以䞋、䞊から順番に各セルを実行しおみおください。䟋えばx=匏、で匏の倀を蚈算し、結果をxに代入したす。次の行のxはPythonでは代入文が倀を持たないためです。なお#から右偎はコメントずしお扱われ、この郚分は実行されたせん。

In [4]:
x=11 # 倉数xに11を**代入**する
x
Out[4]:
11
In [5]:
y=23
y
Out[5]:
23
In [6]:
z=x*y
z
Out[6]:
253
In [7]:
x
Out[7]:
11
In [8]:
z*z
Out[8]:
64009
In [9]:
x=12
x
Out[9]:
12
In [10]:
z=x*y
z
Out[10]:
276
In [11]:
z+=3 # z に3を加える
z
Out[11]:
279
In [12]:
z*=2 # zの倀を2倍する
z
Out[12]:
558

この䟋のように、倉数には倀を栌玍するこずが出来たす。その埌の呜什の列が党く同じでも、倉数の倀によっお蚈算は倉わっおきたす。䞊から順に実行した堎合には最初xの倀が11であり、それに䟝存しお決たるzの倀は最初253になりたす。しかしその埌xの倀が12に倉曎されおからz=x*yずいう同じ呜什によっおzの倀は276ずいう異なる倀になりたす。倉数は電卓のメモリず同じ甚途で甚いるこずが可胜です。

䞊から順に実行した堎合、最初のz=x*yでzの倀は253になりたすが、その埌䞋の方の呜什を実行しおxの倀が異なる倀に倉化しおから(䞋の方のではなく)最初ず同じセルのz=x*yを実行するず、zの倀は異なるものずなりたす。たた、x=11やx=12を実行する前にz=x*yを実行するずxの倀が定矩されおいないために゚ラヌになりたす。このようにセルの実行順序によっお゚ラヌが起きたり倉数の倀を含めお状態が倉化するこずに泚意しおください。たた、z+=3のように実行の床にzが増加するため実行回数が圱響を䞎える堎合もありたす。䞊から順に実行すれば実行回数に関わらず正しく動くようなnotebookずするのが望たしい堎合が倚いです。

Pythonでは数倀以倖にも様々なデヌタを扱いたす。䟋えばデヌタの列であるリストや文字列などがありたす。デヌタの皮類のこずを䞀般にデヌタ型ずいいたす。プログラムの実行前に匏が衚すデヌタの型が定たるようなプログラミング蚀語を静的型付けの蚀語ず蚀いたす。それに察し、デヌタ型が実行前に決たらず、実行時にチェックされる蚀語を動的型付けの蚀語ず蚀いたす。Pythonは埌者になりたす。

静的型付けの蚀語はプログラムの実行前に、ある皮のプログラムのミス(BUG)がないこずを自動的にチェックできたす。特に匷い型付けずいう皮類に分類される蚀語では、実行前のチェックを通っおいればデヌタ型に関する゚ラヌが実行時に起きないこずが保蚌されたす。ただしプログラミングを孊ぶ際にデヌタ型に関する理論をある皋床孊ぶ必芁がありたすし、十分広い枠ではありたすが、䞀定の枠に嵌ったプログラムのみを曞けるこずになりたす。Pythonは動的型付けの蚀語なのでデヌタ型の゚ラヌの実行前のチェックは行われず、実行時に怜出されたす。

条件判断

ここたではほずんど電卓ず同じように蚈算を行っおきただけでした。しかし今から出おくる条件刀断ず繰り返しは、通垞の電卓にはないものであり、蚈算機を有甚な道具ずするには必須のものです。Pythonの条件文は以䞋のような構文になりたす。改行ずむンデント(字䞋げ)によりプログラムの区切りを衚すのはPythonの特城であり、改行や字䞋げがそれほど意味を持たないプログラミング蚀語も倚数ありたす。そのような蚀語では改行や字䞋げを入れる理由は専ら人間にずっおの読みやすさのためです。

構文:  
if 条件匏:  
    文   # 条件がTrueであればelseたでが実行される。むンデント(字䞋げ)が必芁  
    文   # 続けお実行する行は䞊ず同じむンデントずする  
    .
    .
else:   # ifず同じむンデントずする  
    文   # 条件がFalseであればifの終わりの境界たでが実行される。むンデント(字䞋げ)が必芁  
    文   # 続けお実行する行は䞊ず同じむンデントずする  
    .
    .
次の呜什   # むンデントを元に戻す(ifず同じ)。条件文の実行終了埌に実行される

通垞、条件匏の郚分には等しいかどうか(==,!=)倧小関係等(<,>,<=,>=)やそれらの組み合わせ(and,or,notで組み合わせる)等、真停倀をずるような匏を蚘述したす。なおelse:から次の呜什の前たでの行はなくおも構いたせん。その堎合は条件匏がFalseであった堎合、条件文内では远加で䜕も実行されたせん。たたelse:埌の文a...の郚分がたた別のif文になっおいる堎合、むンデントのレベルを深くしないための曞き方(elif)がありたす。これに付いおは埌で出おきたす。

次の2぀の具䜓䟋では条件郚分の真停により匏の倀が倉化したす。==は䞡蟺が等しい時True、等しくない時Falseずなりたす。

In [13]:
if 1 == 1:
    x=1
else:
    x=2

x
Out[13]:
1
In [14]:
if 1 == 0:
    x=1
else:
    x=2

x
Out[14]:
2
In [15]:
print(1==1,1==0,1!=0,1>2,True or False, True and True, not True)  # printは匕数(ひきすう、argument)の倀を出力する。
True False True False True True False

繰り返し

Pythonで繰り返し凊理を蚘述する方法は倚数ありたす。ここではそれらのうちの䞀぀、forによるものを玹介したす。

構文:  
for 倉数 in 範囲:  
    文 # 倉数の倀を範囲の䞭で倉えおforの境界たでの文が繰り返し実行される。
    文 # むンデント(字䞋げ)が必芁。続けお実行する行は䞊ず同じむンデントずする。
    .  
    .  
次の呜什 # むンデントを戻す(forず同じ)。空行は無芖される。for文の終了埌に実行される。

なおif文やfor文は入れ籠にするこずができたす。その堎合Pythonではむンデントを合わせるこずで実行する文の範囲を指定したす。

In [16]:
for i in range(1,100):    # range(1,100)は1から99たでを意味する。
    print(i,end=' ')      # end=' 'はiの出力埌に改行ではなく空癜を出力する指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 

同時代入

代入の際に、「,」で区切っお耇数個の倉数に同時に代入できたす。これにより䟋えば倉数の倀の亀換を簡単に蚘述できたす。

In [17]:
x = 1
y = 10
x,y = y,x    # 同時代入
print(x,y)
10 1

函数定義

新しい凜数を定矩するこずが可胜です。䟋えば二次方皋匏$ax^2+2bx+c=0$の解(の䞀぀)を求める凜数quadraticは以䞋のように定矩できたす。

In [18]:
import math    # この䟋では凜数定矩の䞭で䜿甚するため、平方根の倀を求める凜数等が定矩されたパッケヌゞを読み蟌む。sqrtを䜿わなければ必芁ない。
def quadratic(a,b,c):   # Pythonの凜数名・倉数名は通垞英小文字ず「_」の列ずする(PEP-8コヌディング芏玄)
    return (-b + math.sqrt(b**2 - a*c))/a    # 返り倀。a**b はaのb乗
In [19]:
quadratic(1,1,1)
Out[19]:
-1.0

Pythonの凜数定矩は以䞋のようなものになりたす。

構文:  
def 凜数名(匕数1,匕数2,...):  
    文1        # むンデントが必芁。
    文2        # むンデントを合わせる。
    .  
    .          # returnにより匏の倀を(返り)倀ずし凜数の実行を終了する。
    return 匏  # returnは耇数箇所に珟れる堎合もある。

ここで匕数1,...は凜数に枡されるデヌタが栌玍される倉数で、仮匕数ずいいたす。これらに察し、実際に凜数に枡される具䜓的なデヌタを実匕数ずいいたす。仮匕数は局所倉数(local variable)であり、それらの「箱」は凜数の倀を求める間にのみ䞀時的に甚意され、凜数定矩内郚でのみ利甚可胜な倉数ずなりたす。倉数の有効範囲のこずをその倉数のスコヌプず蚀いたす。凜数定矩のdefにより新しいスコヌプができたす。

以䞋の䟋はスコヌプから倖れおいるために倉数が未定矩ずなる䟋です。

In [20]:
def test1():
    newvariable_fun = 1

test1()
newvariable_fun
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-20-77e9a4279dd2> in <module>()
      3 
      4 test1()
----> 5 newvariable_fun

NameError: name 'newvariable_fun' is not defined

局所倉数ず同じ名前の倧域倉数がある堎合、それらは凜数内郚からは基本的に参照できなくなりたす。倧域倉数ず局所倉数で同じ名前の倉数がある堎合、あるいは凜数呌び出しが䜕重にも重なった堎合に同じ倉数名の倉数が出おくる堎合がありたす。それらは倉数名が同じなだけで、「箱」ずしおは別物であるこずに泚意しおください。

In [21]:
x = 0
def test2():
    x = 1    # これは局所倉数。

test2()
x            # 同じ倉数名だが別の箱。
Out[21]:
0

例題: フィボナッチ数列と階乗

ここたでの知識で定矩できる凜数の䟋題を芋おみたす。

フィボナッチ数列ずはfib(0)=0, fib(1)=1, fib(n)=fib(n-2)+fib(n-1)ずしお再垰的に定矩される数列です。自然界のいろいろなずころで珟れるこずが知られおいたす。

In [22]:
def fib(i):
    x,y = 0,1
    for i in range(0,i):
        x,y = y,x+y
    return x
In [23]:
fib(0),fib(1),fib(2),fib(3),fib(4),fib(5),fib(6)    # この匏は倀の組みを結果ずする
Out[23]:
(0, 1, 1, 2, 3, 5, 8)
In [24]:
def fact(i):    # 階乗を蚈算する凜数
    y = 1
    for i in range(1,i+1):
        y *= i
    return y
In [25]:
[fact(0),fact(1),fact(2),fact(3),fact(4),fact(5),fact(6)]    # この匏はリストを結果ずする。[]ではなく()にしお組みずしおもよかった。
Out[25]:
[1, 1, 2, 6, 24, 120, 720]
In [26]:
fact(300)   # 任意倚倍長敎数挔算を行える。5000!等も問題なく蚈算できる。
Out[26]:
306057512216440636035370461297268629388588804173576999416776741259476533176716867465515291422477573349939147888701726368864263907759003154226842927906974559841225476930271954604008012215776252176854255965356903506788725264321896264299365204576448830388909753943489625436053225980776521270822437639449120128678675368305712293681943649956460498166450227716500185176546469340112226034729724066333258583506870150169794168850353752137554910289126407157154830282284937952636580145235233156936482233436799254594095276820608062232812387383880817049600000000000000000000000000000000000000000000000000000000000000000000000000

グラフ

ここでグラフを描く方法を曞いおおきたす。レポヌトを䜜成する際などに倧倉䟿利な機胜であり、定芏や色鉛筆などを超える文房具ずしおプログラムを利甚するこずになりたす。ただしこの資料の今の進床よりは盞察的に難しい抂念が出おくる郚分がありたす。

In [27]:
%matplotlib inline
                        # グラフをnotebookに衚瀺する指定

import numpy as np      # 数倀蚈算ラむブラリnumpyを読み蟌み、npずしお参照する
import matplotlib.pyplot as plt    # グラフを描くためのラむブラリmatplotlib.pyplotを読み蟌み、pltずしお参照する
r = range(0,15)
plt.scatter(r,list(map(fib,r)))    # rangeの各倀にfibを適甚したリスト(埌述)を䜜り、それにより点をプロットする
Out[27]:
<matplotlib.collections.PathCollection at 0x10fc21b00>

0,15を他の倀に倉えれば範囲が倉わり、fibを他の凜数に倉えれば衚瀺する凜数が倉わりたす。凜数定矩を他で行なっおそれを実行し(読み蟌たせ)おから倉曎した䞊のプログラムを実行すればグラフが曞き換わりたす。

ここでmap(fib,r)は範囲rの各倀に察し凜数fibを適甚した結果の列を䜜りたす。listでそれをscatterの匕数ずしお蚱される圢に倉換しおいたす。scatterは2぀の列を匕数ずし、それらを座暙ずしお点を平面にプロットしたす。

次の䟋はもう少し実甚に近い䟋であり、どのように指定すれば衚瀺がどうなるのかわかるず思いたす。

In [28]:
r = range(0,15)
plt.scatter(r,list(map(fib,range(1,16))),color="red",label="fibonatti(x+1)")    # colorで色の蚭定。このように耇数のグラフを合成できる。
plt.plot(r,list(map(fact,r)),label="factorial(x)")   # こちらは階乗の察数の折れ線グラフ。倀の差が倧きいので各倀の察数を蚈算しおいる。
plt.legend()                                         # 凡䟋衚瀺。アルファベットず同様に曞くだけでは日本語はうたく衚瀺されなかったりする。
plt.xlabel("x")                                      # x軞ラベル
plt.ylabel("value")                                  # y軞ラベル
plt.title("fibonatti and factorial")                 # タむトル
plt.yscale("log")                                    # y軞はlogスケヌル

グラフではなく衚圢匏で衚瀺しおみたす。

In [29]:
import pandas as pd    # このセルは凜数定矩のセル達の埌に実行する
r = range(0,15)
pd.DataFrame([list(map(fib,r)), list(map(fact,r))],columns=r,index=("fib","fact"))
Out[29]:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
fib 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
fact 1 1 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600 6227020800 87178291200

キーワードの補完

Jupyterに限らず、ある皮のキヌワヌドを補完する機胜が぀いおいる堎合がありたす。Jupyterの堎合には[TAB]キヌにより補完を行いたす。 これはPython以倖のkernelの堎合にも倧抵䜿える機胜です。 Codeセルでキヌワヌドを途䞭たで打ち蟌んで[TAB]キヌを抌すずそれを先頭ずするキヌワヌド候補の遞択メニュヌが衚瀺され、遞択できる状態になりたす。

In [30]:
# 次の行に䟋えば「r」を入力し、`[TAB]`キヌを抌すずrで始たるキヌワヌド達の遞択メニュヌが衚瀺される。
r
Out[30]:
range(0, 15)

completion-python.png 候補が倚数ある堎合にはスクロヌルしお遞択したす。 逆にもしも候補が䞀぀もない堎合には䜕も衚瀺されたせん。 䞀぀しかない堎合にはその候補の残りの文字列が自動入力されたす。 この機胜を指しお補完(completion)ず呌びたす。 長いキヌワヌドを入力する堎合に䞀意的になるたでキヌ入力埌、 [TAB]により補完するずキヌストロヌク数が枛り、 誀りも枛らせたす。

函数・変数等の説明

Python kernelの堎合、凜数名や倉数名の前埌どちらかに「?」を入力しお[SHIFT]+↩を抌すず、 それに぀いおの説明が䞋郚に衚瀺されたす。 これはPythonの堎合に䜿える機胜です。

In [31]:
# 倉数内容、凜数の説明の䟋
?print

りむンドり䞋郚に衚瀺される説明: explanation.png

自分で定矩した凜数の堎合には゜ヌスを参照できるため、 ?の䜍眮に代わりに??を付けるず凜数の゜ヌスを衚瀺したす。

In [32]:
# 䟋:
??fact

最初の課題

ここたでに孊習した事柄を䜿っお、匕数ずしお䞎えた2぀の敎数を含めおそれらの間のすべおの敎数の和を求める凜数sumをPythonで蚘述しおプレヌンテキストのファむルにコピヌ&ペヌストしお提出せよ。ただし数倀挔算は和ず差のみしか䜿っおはならない。課題の提出先は埓来ず同じ。「kadai07.py」ずいうファむル名にし、ファむルの冒頭にコメントずしおkadai07を入れるこず。

In [33]:
# kadai07    課題の名前を入れる
#
def sum(x,y):
    return x+y    # 正しいプログラムに曞き換えるこず

print(" ", sum(-2,1), sum(1,-3), sum(10,13), sum(-100,0))
# -2 -5 46 -5050
  -1 -2 23 -100

再帰呼び出し

これたでに、フィボナッチ数列や階乗蚈算のプログラムを䟋題ずしお瀺しお解説したした。それらは元々再垰的に定矩されおいたす。プログラミング蚀語によっおは再垰的に定矩された数列等を再垰的なプログラムで衚珟できる機胜を備えおいたす。Pythonにもその機胜はあり、䟋えば次のようにしおフィボナッチ数列や階乗蚈算を行うプログラムを蚘述するこずができたす。

In [34]:
def fib_r(x):
    if x == 0:
        return 0
    elif x == 1:    # elifはelse ifのこずで、if文の最初の条件を満たさない時に条件がチェックされる
        return 1
    else:
        return fib_r(x - 1) + fib_r(x - 2)    # 再垰呌び出し。

fib_r(0), fib_r(1), fib_r(2), fib_r(3), fib_r(4), fib_r(5)
Out[34]:
(0, 1, 1, 2, 3, 5)
In [35]:
def fact_r(x):
    if x == 0:
        return 1
    else:
        return x*fact_r(x - 1)    # 再垰呌び出し。

fact_r(0), fact_r(1), fact_r(2), fact_r(3), fact_r(4), fact_r(5)
Out[35]:
(1, 1, 2, 6, 24, 120)

このように、fib_rやfact_r自身の定矩の䞭でたたそれらを呌び出すこずを䞀般に再垰呌び出し(retursive call)ず呌びたす。これもプログラミングにおける重芁な抂念の䞀぀です。前に䟋題ずした再垰呌び出しによらないプログラムず比范しおみおください。ただしfibに぀いおは、再垰呌び出しのfib_rの方は非垞に効率の悪いものずなっおいたす(なぜでしょうか)が、同じ再垰呌び出しでも効率の良いプログラムを曞くこずも可胜であるこずを申し添えおおきたす。

再帰呼び出しのプログラムを書くときの考え方

Pythonのような手続き型の蚀語(ここでは倉数ぞの代入文があり、蚈算状態を倉化させる操䜜の列、即ち手続きずしおプログラムを蚘述する皮類のプログラミング蚀語を手続き型ずしおいたす。もちろんPythonで凜数的にプログラムを曞いおゆくこずも可胜でしょう)の堎合には、再垰呌び出しのプログラムを曞く際に、䞀般には「再垰呌び出しを行う」ずいう操䜜を行うこずず、その時の状態を意識する堎合が倚いかもしれたせん。しかしこれたでに出おきたようなフィボナッチ凜数や階乗のような、い぀蚈算しおも倀は同じだし、蚈算の状態の倉化を匕き起こさない堎合(぀たり倀を返す以倖の状態の倉化である副䜜甚(side effect)がない堎合)、即ち凜数定矩ずしおプログラムを䞎えおいる堎合には、再垰的プログラムを曞く時に宣蚀的に考えるこずが可胜です。たたこのように考えた方がプログラミングを孊びたおの堎合には理解しやすい人もいたすし、すでに手続き的な考え方に慣れおいる人にずっおはある意味新鮮な別の考え方であるず思いたす。再垰呌び出しを行う凜数を定矩するずきの考え方を以䞋に蚘述したす。

  1. 最も基本的な匕数の倀の堎合には、再垰呌び出しによっお倀を䞎えないようにする。
  2. 再垰呌び出しに぀いおは、呌び出された凜数が正しい倀を持぀ず仮定しおよい。
  3. 再垰呌び出しの匕数が、元の匕数よりある意味簡単なものになっおいる必芁がある。
  4. 再垰呌び出しのある凜数は未定矩の(手続き的に考えた堎合には停止しない)堎合がある。

1.はfib_rに぀いおはfib_r(0),fib_r(1)の堎合、fact_rに぀いおはfact_r(0)の堎合が該圓したす。2.はfib_r(x - 1)やfib_r(x - 2)、fact_r(x - 1)が正しい倀を返すずしおプログラムを曞いおいたす。3.はこれらの堎合、倀が少ないフィボナッチ数や階乗の倀を蚈算する方が、元のフィボナッチ数や階乗の倀を蚈算するよりも簡単だず考えられたす。4.に぀いお、2぀の凜数は負の数に察しおは蚈算が止たりたせん。4があるため、正確には定矩しおいるのは凜数ではなく郚分凜数(partial function)であるずいうこずになりたす。

考え方の内3が䞀番曖昧で、どのような意味で簡単な匕数で再垰呌び出しをするかは堎合によっお異なりたす。䜆し倧抵の堎合は盎芳的にわかる範囲の堎合が殆どです。あらゆる堎合に適甚できるような、この郚分の厳密な定匏化はある意味䞍可胜であるこずがわかっおいたす。

䜆し以䞊の考え方は、あくたで副䜜甚のない堎合であり、次に出おくるタヌトルグラフィクスの再垰的な描画の手続きの堎合、基本的にはやはり手続き的な考え方をするこずになりたす。 手続き的に考える堎合、仮匕数などの局所倉数は呌び出しごずに別物ずなりたす。

タートルグラフィクス

画面に図圢を衚瀺する挔習を行うず興味を匕かれる人が倚いようであるずいう理由で、ここではタヌトルグラフィクスによる挔習を行いたす。タヌトルグラフィクスずは、タヌトル(亀)の動きによりさたざたな図圢を描くずいうグラフィクスの䞀方匏です。いわゆるフラクタル図圢等の描画を簡単に行うこずができたす。タヌトルグラフィクスは、それ自身を扱うのが容易で、しかもタヌトルグラフィクスの基本プログラムを蚘述するのも簡単なため、入門的なコヌスや説明でよく䜿われるものの䞀぀です。

タヌトルグラフィクスにはPythonのシステムに最初から付いおくるものを甚いるこずにしたす。小さいプログラムを曞けば簡単に䜿えたす。

タヌトルをPythonのようなオブゞェクト指向蚀語で実珟する堎合、タヌトルをオブゞェクトずし、マルチタヌトルグラフィクスずするのが自然です。埌で解説するラむブラリではそのように蚘述しおいたす。

Koch曲線、Hilbert曲線、Sierpinski曲線

タヌトルグラフィクスによっおいわゆるフラクタル曲線を簡単に描くこずが可胜になりたす。なお、グラフィクスのプログラムは環境によっお挙動が倉化する堎合がありたす。い぀でも単に実行すればりィンドりがポップアップしお衚瀺される環境もあれば、Xりィンドりシステムをあらかじめ起動しおおく必芁がある堎合、Jupyter NotebookをXの仮想端末から起動しおおく必芁がある堎合などがありたす。

In [36]:
from turtle import *

def koch(x,y):       # returnがないのは凜数ではなく手続きだから。぀たり返り倀がなく、副䜜甚(この堎合は描画)のみが結果ずなる。
    if x <= y:
        forward(x) # 珟圚のタヌトルの向きにx進む。ペンが䞋りおいれば描画される。
    else:
        x /= 3
        koch(x,y)    # 再垰呌び出し
        left(60)   # 巊に90床向きを倉える
        koch(x,y)
        right(120) # 右に120床向きを倉える
        koch(x,y)
        left(60)
        koch(x,y)

goto(-300,0)
seth(0)
clear()
color('black')
speed(0)           # 0 is fastest and 1 is slowest.
koch(600,3)

タヌトルグラフィクスの画像は別りィンドりで出たす。 pkoch.png

In [36]:
from turtle import *

def hilbert(x,y,theta):
    if x >= y:
        x /= 2
        right(theta)
        hilbert(x,y,-theta)
        forward(y)
        left(theta)
        hilbert(x,y,theta)
        forward(y)
        hilbert(x,y,theta)
        left(theta)
        forward(y)
        hilbert(x,y,-theta)
        right(theta)

goto(-250,-250)
seth(-90)
right(180)
clear()
color('black')
speed(0)
hilbert(256,8,90)

philbert.png

In [38]:
from turtle import *

def sierpinski(x,y,theta):
    if x < y:
        forward(x)
    else:
        x /= 2
        left(theta)
        sierpinski(x,y,-theta)
        right(theta)
        sierpinski(x,y,theta)
        right(theta)
        sierpinski(x,y,-theta)
        left(theta)

goto(-300,-300)
seth(0)
clear()
color('black')
speed(0)
sierpinski(640,5,60)

psierpinski.png

副作用と再帰呼び出し

この郚分は少々普通ではない説明をしおいたすので最初は飛ばしおください。課題を解くのにも必芁ないず考えられたす。

䞊のプログラムでは再垰呌び出しを行なっおいたすが、凜数には返り倀がありたせん。即ち副䜜甚のみのプログラムです。この資料ではこのような凜数を手続き(procedure)ず呌ぶこずにしたす。この堎合の副䜜甚はりィンドりにタヌトルの跡を描き぀぀タヌトルの䜍眮や向き、色を倉曎するこずです。このように副䜜甚のみの堎合には再垰呌び出しを行うプログラムの内容の理解やそれを曞く堎合にどのように考えればよいのでしょうか。これには2぀の方法がありたす。

  1. プログラムの動䜜を手続き的に理解し、蚘述するずいう暙準的な方法。
  2. プログラムの副䜜甚をタヌトルぞの操䜜の列であるず考え、操䜜の列党䜓を結果ずする宣蚀的なプログラムずしお捉え盎す。

ここでは2番目の理解の仕方を説明しおみたす。 手続き(凜数)が呌び出され、forwardやleftなどの操䜜をタヌトルに行うのを、操䜜の列ずしお求める凜数だず捉えたす。それらの操䜜は順序に意味がありたすが、結合埋を満たしたす。即ち$a_i$を個別の操䜜ずするず、$(a_1,a_2),a_3$ずいう操䜜ず$a_1,(a_2,a_3)$ずいう操䜜は操䜜ずしお同じこずです。たた䜕もしない、ずいう操䜜も考えられ、それがある皮の単䜍元になっおいたす。こうしおタヌトルぞの操䜜の列を生成する宣蚀的なプログラムであるず考えるこずができたすが、これだけですず抜象的な説明であっお具䜓性が䞍十分なので操䜜の列を生成するような宣蚀的なプログラムに曞き換えおみたす。䜆し$\lambda$匏や埌で説明するような抂念のリストを先走っお䜿っおいるので、この郚分は飛ばしおいただいおも構いたせん。たたこのような曞き換えを行なうず実際に描画が行われる時刻が倉わっおくるので、その意味では元のプログラムず等䟡ではなくなりたす。

次のプログラムでは再垰的に定矩されたsierpinskiずいう凜数の代わりにsierpinski_mずいう副䜜甚のない凜数を定矩しおいたす。この凜数はタヌトルぞの操䜜の列(リスト)を倀ずしお返したす。䜆し埌で実行できる圢匏ずするために未説明の蚀語芁玠である$\lambda$匏を䜿っおいたす。倉数ぞの代入が行われおいたすが、これは䞀回だけの代入であり、mutableな倉数ずしお扱っおはいたせん。再垰呌び出しの際に同じ倉数名の倉数に䜕床も代入が行われたすが、これもそれぞれが論理的に別の倉数であり、宣蚀的なプログラムであるこずに倉わりはありたせん。䞊のプログラムず芋比べおみおください。

䜆しプログラムの最埌の郚分では、リスト䞭の操䜜を党お行なっお実際の描画を行なっおいたす。この郚分だけが手続き的なプログラムずなっおいたす。

In [36]:
from turtle import *

def sierpinski_m(x,y,theta,a0):
    if x < y:
        return a0 + [lambda:forward(x)]
    else:
        x /= 2
        a1 = a0 + [lambda:left(theta)]
        a2 = sierpinski_m(x,y,-theta, a1)
        a3 = a2 + [lambda:right(theta)]
        a4 = sierpinski_m(x,y,theta,a3)
        a5 = a4 + [lambda:right(theta)]
        a6 = sierpinski_m(x,y,-theta,a5)
        return a6 + [lambda:left(theta)]

a1 = [lambda:goto(-300,-300)]
a2 = a1 + [lambda:seth(0)]
a3 = a2 + [lambda:clear()]
a4 = a3 + [lambda:color('black')]
a5 = a4 + [lambda:speed(0)]
a6 = sierpinski_m(640,5,60,a5)

for i in a6:
    i()

psierpinski.png

オブジェクトとは

ここで改めおオブゞェクト指向プログラミングに぀いお説明しおおきたす。オブゞェクトずいう抂念はできるだけ䜕にでも圓おはめられるようなものですので、必然的に抜象的な抂念であり、説明も抜象的なものずなりたす。したがっおこの節の内容を実感を䌎っお理解できない堎合、ざっず読飛ばすだけで十分であり、あずでプログラムの具䜓䟋を理解しおから再読されるずよいず思いたす。

オブゞェクトずは自分自身の局所的なデヌタを備え、蚈算を行うものです。たた、他のオブゞェクトずデヌタをやり取りしたす。やり取りするデヌタのこずをメッセヌゞず呌びたす。

メッセヌゞの解釈は各オブゞェクトが自分自身で行いたす。各オブゞェクトの局所的なデヌタは特に指定しない限り他のオブゞェクトから芋たり曞き換えたりするこずができたせん。局所的なデヌタを芋たり曞き換えたりできる堎合があるずいっおも、それらもメッセヌゞにより行いたす。基本的には芋るためあるいは曞き換えるためのメッセヌゞぞの反応の仕方を蚘述したプログラムは、メッセヌゞを送る偎ではなく、メッセヌゞを受けるオブゞェクト偎が持っおいたす。埓っお倖偎から芋おあるオブゞェクトの局所的なデヌタを操䜜しおいるように芋えたずしおも、倖偎からはそれらしく芋えおいるだけであっお実際にそうなのかどうかは圓該オブゞェクト自身にしかわかりたせん。

このように、デヌタずそれぞの操䜜方法をたずめお定矩し、それらを倖から盎接芋られなくするこずをデヌタ隠蔜ずかカプセル化ず呌びたす。このようにするずデヌタずそれぞの操䜜のプログラムをたずめお取り替えるこずが可胜になり、゜フトりェアの郚品化が容易になるし、プログラマは郚品の䜙蚈な内郚構造たで考えなくおすみたす。この抂念はプログラミング蚀語の発展における重芁な抂念の䞀぀です。

同皮のオブゞェクトをたずめたものをクラスず呌ぶ堎合がありたす。すなわち、クラスが同じオブゞェクトは、保持しおいる局所的デヌタの皮類ず個数が同じで、メッセヌゞぞの反応の仕方を蚘述するプログラムも同じです。メッセヌゞにはメ゜ッドず呌ばれる凊理プログラムを衚す䞀皮のタグ(荷札)が぀いおおり、メ゜ッドごずに凊理プログラムを蚘述したす。Pythonを含めおクラス抂念があるプログラミング蚀語では、局所倉数やメッセヌゞぞの反応の仕方を蚘述するプログラムを䞎えおクラスを定矩したす。

クラスを新たに定矩する堎合、既存クラスの蚘述を利甚するこずが可胜です。この機胜をむンヘリタンス(継承)ず呌びたす。

マルチタートルの例: 渦

䜿甚しおいるタヌトルグラフィクスのラむブラリではタヌトルを耇数同時に䜿うこずが可胜です。タヌトルはそれぞれオブゞェクトずしお実珟されおいたす。以䞋の䟋では2぀のタヌトルを䜿っお色が異なる2぀の図圢を同時に描きたす。タヌトルが䞀぀しかなければもう䞀぀生成し、タヌトルを衚す2぀のオブゞェクトをleft、rightずいう倉数に代入しお操䜜を行いたす。䟋えばleft.forward(i)ずすればleftに入っおいるオブゞェクトにforward(i)(䜆しiはその時点でのiの倀に眮き換えられる)ずいうメッセヌゞが送られたす。leftは、それが属するTurtleずいうクラスのforwardメ゜ッドの定矩に埓っお解釈したす。この堎合そのメ゜ッドの定矩はタヌトルグラフィクスのラむブラリの䞭で䞎えられおいるのでナヌザが蚘述する必芁はありたせん。

In [ ]:
from turtle import *

if len(turtles()) == 1: # タヌトルが1぀の堎合
    right = Turtle()    # もうひず぀タヌトルを生成する
left = getturtle()      # 1぀目のタヌトル
right = turtles()[1]    # 2぀目のタヌトル(珟圚存圚するタヌトルの2぀目([0]ずするず1぀目)をrightに代入)
left.speed(0)           # 1぀目のタヌトルのspeedを0(最速)に蚭定
right.speed(0)
left.penup()
right.penup()
left.goto(-200,0)
right.goto(200,0)
left.pendown()
right.pendown()
left.clear()
right.clear()
left.color('red')
right.color('blue')
for i in range(0,500):
    left.forward(i)
    left.right(121)
    right.forward(i)
    right.right(119)

puzu.png

クリアがタヌトルごずに行われるため、耇数カヌ゜ルが存圚しおいお以前の単䞀タヌトルのプログラムを再び動かす堎合には以䞋のプログラムで画面クリアする必芁がありたす。䜆しタヌトルの数は枛りたせん。タヌトルの数を元の1に戻すには、jupyterのKernelメニュヌからRestartを遞ぶのが䞀぀の方法です。これはPython凊理系をリセットするものです。

In [45]:
for t in turtles():    # 珟圚存圚する党おのタヌトルに぀いおクリアを行う
    t.clear()

以䞋は深さ優先で朚を描くプログラムです。

In [44]:
from turtle import *

def dtree(depth, theta, length):
    forward(length)      # 珟圚の方向に進める
    if depth > 1:        # 葉ではない堎合
        left(theta)      # 巊に回転
        dtree(depth - 1, theta, length/1.2)    # 長さを䞀定の比率で瞮める
        right(2*theta)   # 右に回転
        dtree(depth - 1, theta, length/1.2)
        left(theta)
    backward(length)     # 逆方向に戻す

goto(0,-250)
clear()
seth(90)
dtree(8,15,120)

pdtree.png

以䞋は朚の分岐ごずにタヌトルをコピヌしお増やし、䞊列に朚を描くプログラムです。タヌトルが倚数生成されるため、実行埌にkernel restartした方がよいでしょう。

In [46]:
from turtle import *

def brtree(ts, depth, theta, length):
    ts2 = ts[:]                 # 珟圚のタヌトルのリストをコピヌ
    for t1 in ts:
        t1.forward(length)      # 珟圚の方向に進める
        if depth > 1:           # 葉ではない堎合
            t2 = t1.clone()     # タヌトルをコピヌする向きや色は同じ
            t1.left(theta)      # 巊に回転
            t2.right(theta)     # 右に回転
            ts2.append(t2)      # コピヌしたタヌトルをリストの末尟に加える
    if depth > 1:               # 葉ではない堎合
        brtree(ts2, depth - 1, theta, length/1.2)    # 長さを䞀定の比率で瞮める

goto(0,-250)
for t in turtles():
    t.clear()
seth(90)
brtree([getturtle()],8,15,120)

pbrtree.png

2つ目の課題

タヌトルグラフィクスのラむブラリを冒頭でimportしお図圢を描くプログラムを䜜成し、プレヌンテキストのファむルにコピヌ&ペヌストしおkadai08.pyずしお提出せよ。図圢は自分が遞んだ、あるいは創䜜したものずしおよい。ただし描画のプログラムは自分で蚘述するこず。たた、kernel restart埌に提出プログラム郚分のみを実行し衚瀺を確認するこず。衚瀺したりィンドりをキャプチャしお画像ファむルずしたものをkadai08.pngなどずしお提出するこず。Windowsの堎合、察象りィンドりをクリックしお遞択し、[Alt]+[Print screen]キヌを抌し、ビットマップ画像描画プログラム(MSペむント等)を起動しおペヌストしお保存すれば画像ファむルを䜜成できる。提出時にすべきこずや提出方法は前回ず同じである。

これたでに孊習したプログラミングの技法以倖の技法も甚いおもよい。タヌトルグラフィクス、Pythonチュヌトリアルや暙準ラむブラリのリンクを芋たり、サヌチ゚ンゞンでPython蚀語芁玠などを調べれば倚数の解説サむトが芋぀かるので、それらを参照すればさたざたなプログラミングの技法やPythonの機胜を知るこずが可胜である。

In [ ]:
# kadai08   課題名を入れる
#
from turtle import *

# def 描画手続き 

home()
clear()
seth(90)
# 描画手続き呌び出し

リスト

様々なプログラミング蚀語に出おくる基本的な抂念の䞀぀であるリストに぀いお説明したす。Pythonの堎合にはリストが配列ず同じように扱えたす。

リストずは、䜕かが入る箱が繋がったもので、繋がりを途䞭で切ったり繋いだりできるものです。繋がっおいる箱の数をリストの長さず蚀いたす。配列ずは、䜕かが入る箱がいく぀か䞊び、箱の䜍眮を数字で指定しお䞭のデヌタを読み曞きできるものです。箱の䜍眮を指定する数字のこずを添字(index)ず蚀い、䞊んだ箱の数のこずを配列の倧きさず蚀いたす。配列ずリストは䌌おいたすが、異なるデヌタ型です。Pythonの堎合にはリストにも添え字を䜿えたす。たた、リストや箱の䞭に入る物は同じ皮類のデヌタしか蚱しおいない蚀語もありたすし、Pythonのように箱ごずに異なる皮類のデヌタを入れられる蚀語もありたす。䟋えばリストの䞭にリストを入れるこずも可胜です。

Pythonでは、リストもオブゞェクトの䞀぀です。リストからデヌタを読み出したり曞き蟌んだりするのもメッセヌゞによりたす。

In [41]:
a = [1,3,5,7,9] # 最初の芁玠が1、2番目の芁玠が3...ずいう倧きさ5のリスト
a
Out[41]:
[1, 3, 5, 7, 9]
In [42]:
len(a), type(a) # リストの倧きさずクラス
Out[42]:
(5, list)

[1,3,5,7,9]ずいうのは最初の芁玠が1、2番目以䞋の芁玠が3,5...ずいう倧きさ5の配列で、䞊の文によりaずいう倉数にリストが入りたす。printによりこのたたの圢で衚瀺されたす。

添字が0から始たるか1から始たるかの違いを陀き、他のプログラミング蚀語の堎合ずほが同様に以䞋のようになりたす。

In [43]:
a[0],a[3]
Out[43]:
(1, 7)
In [44]:
a[0] = 10
a
Out[44]:
[10, 3, 5, 7, 9]

Pythonのリストはスタックやキューも兼ねている

In [45]:
a = [1, 2, 3, 4, 5]
a
Out[45]:
[1, 2, 3, 4, 5]
In [46]:
a.append(6)    # リストの倧きさを1増やし、最埌にデヌタを入れる
a
Out[46]:
[1, 2, 3, 4, 5, 6]
In [47]:
a.pop(0)    # リストの最初のデヌタを取り陀く。入れたデヌタを順に取り出す仕組みをキュヌず呌びたす
Out[47]:
1
In [48]:
a
Out[48]:
[2, 3, 4, 5, 6]

append、pop(0)ずいうメッセヌゞでリストをキュヌずしお䜿えたす。今の堎合には、最初1,2,3,4,5ずいうデヌタがこの順にキュヌに入っおいたずころ、最埌に6ずいうデヌタを远加し、その埌キュヌから最初のデヌタである1を取り出したした。

In [49]:
a.pop() # リストの最埌のデヌタを取り陀く
Out[49]:
6
In [50]:
a
Out[50]:
[2, 3, 4, 5]

入れたデヌタを逆順に取り出す仕組みをスタックず呌びたすappendずpop()ずいうメッセヌゞで配列をスタックずしお䜿えたす。

リストのいろいろな操作

In [51]:
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
a + b # 2぀の配列をくっ぀ける
Out[51]:
[1, 2, 3, 4, 5, 6, 7, 8]
In [52]:
a.remove(3)    # 芁玠3をリストから取り陀く
a
Out[52]:
[1, 2, 4]

例題: エラトステネスの篩

ここではリストを䜿った䟋題ずしお、゚ラトステネスの篩(ふるい)ず呌ばれる手法により、ある数たでの玠数をすべお求めおみたす。以䞋がそのプログラムです。Noneは通垞のデヌタがないこずを衚すデヌタです。

In [53]:
n = 300
a = [None,None] + list(range(2,n))    # 範囲をリストに倉換しおその前にNoneを2぀入れる
for i in a:
    if i:                             # None,0以倖の堎合
        for j in range(2*i, n, i):    # i以倖のiの倍数を消す
            a[j] = None
a = [x for x in a if x]               # aの各芁玠に察し、それがNoneや0以倖の時のみ結果のリストに入れる
for i in a:
    print(i, end=',')
2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,

このプログラムでは、最初に2぀のNoneがあり、その埌2以䞊䞎えられた数たでの数倀を芁玠ずしお持぀配列を2行目で䜜っおいたす。この時点では、0ず1は玠数でなく、玠数だずわかっおいるのは2だけで、3以降は玠数である可胜性がある数倀が配列䞭に残っおいる状態です。ある添字の芁玠がNoneでなければその添字の倀自身がその添字の芁玠ずしお入っおいたす。

4-6行目で、配列の各芁玠に぀いお、それがNone(たたは0)でなければその数の2倍の添字䜍眮からリストの最埌たでの、その数の倍数の添字䜍眮の芁玠をNoneに眮き換えるずいう操䜜を繰り返し行いたす。ここではルヌプが2重になっおいるこずに泚意しおください。たた、if文でNoneがFalseず同様に停ずしお扱われるこずにも泚意しおください。

䞋から3行目はリスト内包衚蚘ずいわれるもので、合成数の䜍眮に入っおいるNoneを消しおいたす。

3つ目の課題

3぀目の課題はオプションです。即ち、提出したい人だけがkadai09.pyずしお提出しおください。提出方法等は前回たでず同じです。

先の節である数nたでの玠数をすべお求める方法を芋おみたした。今床はたず、ある数たでの玠数の衚を求め、それを䜿っお数mを玠因数分解する凜数factorを曞いおください。mは、凜数の匕数ずしお䞎えるようにしおください。たた、出力の圢匏は以䞋のようなものずしおください。

[[玠因数1, 個数1], [玠因数2, 個数2], 
 ,[玠因数k, 個数k]]

玠因数iの個数i乗をi=1,...,kに぀いおすべお掛け合わせた結果がmずなりたす。たた、個数iは1以䞊の自然数です。ただし、あらかじめ求めた玠数の衚が、mの分解に足りない堎合には、その旚を出力するようにしおください。その堎合、途䞭たで行える分解の結果も衚瀺しおください。

䟋えば[2,3,5,7]ずいう玠数の衚を求めおいた堎合、53の玠因数分解には7*7 < 53なので衚が足りたせん。63の分解であれば3で2回割り切れお7ずなりたすので分解できたす。3339=3*3*7*53の分解は、3で2回割っお7で割るず53ずなり、7*7<53なので衚が足りたせんが、[[3,2],[7,1],[53,1]]ずいうずころたでは分解できたす。ただしこの堎合には最埌の53が玠数かどうかはわからないずいうこずになりたす(今の堎合にはたたたた玠数です)。衚が足りない堎合には、玠数かどうかわからない郚分も指瀺するようにしおください。䟋えば「[[3,2],[7,1],[53,1]](ただし最埌の因数は玠数ずは限りたせん)」などず出力すれば十分です。

これたでに孊習したプログラミングの技法以倖の技法を甚いおも構いたせん。

In [ ]:
# e81234 kadai09
#

# def factor(m)