[Python3 入門 21日目]10章 システム（10.1〜10.5）

#10.1 ファイル
##10.1.1 open()による作成

- open()関数はファイルを開くだけでなく、存在しないファイルを要求したときは新しいファイルが作られる。

```py

>>> fout=open("oops.txt","wt")
>>> print("Oops,I created a file.",file=fout)
>>> fout.close()

```

##10.1.2 exists()によるファイルが存在することのチェック

```py

>>> import os
>>> os.path.exists("oops.txt")
True
>>> os.path.exists("./oops.txt")
True
>>> os.path.exists("aaa.txt")
False
>>> os.path.exists(".")
True
>>> os.path.exists("..")
True

```

##10.1.3 isfile()によるファイルタイプのチェック

```py

>>> name="oops.txt"
>>> os.path.isfile(name)
True
#ディレクトリかどうかisdir()を使う。
#"."はカレントディレクトリを表す
#".."は親ディレクトリを表す
>>> os.path.isdir(name)
False
>>> os.path.isdir(".")
True
>>> os.path.isdir("..")
True
#isabs()は引数が絶対パスかどうかを返す。
>>> os.path.isabs(name)
False
>>> os.path.isabs("/big/fake/name")
True
>>> os.path.isabs("/big/fake/name/without/a/leading/slash")
True
>>> os.path.isabs("big/fake/name/without/a/leading/slash")
False

```

##10.1.4 copy()によるコピー

```py

>>> import shutil
>>> shutil.copy("oops.txt","ohono.txt")
'ohono.txt'

```

##10.1.5 rename()によるファイル名の変更

```py

>>> import os
>>> os.rename("ohono.txt","ohwel.txt")

```

##10.1.6 link()、symlink()によるリンクの作成
 
```py

#yikes.txtからoops.txtへのハードリンク作成
>>> os.link("oops.txt","yikes.txt")
>>> os.path.isfile("yikes.txt")
True
jeepers.txtからoops.txtへのシンボリックリンク作成
>>> os.symlink("oops.txt","jeepers.txt")
>>> os.path.islink("jeepers.txt")
True

```
##10.1.7 chmod()によるパーミッションの変更

```py

#oops.txtに読み出しのみ認める。
>>> os.chmod("oops.txt",0o400)

>>> import stat
>>> os.chmod("oops.txt",stat.S_IRUSR)

```

##10.1.8 chown()によるオーナーへの変更

```py

>>> uid=5
>>> gid=22
>>> os.chown("oops",uid,gid)

```
##10.1.9 abspath()によるパス名の取得

```py

#相対名を絶対名に拡張する。
>>> os.path.abspath("oops.txt")
'/Users/practice/bin/oops.txt'

```
##10.1.10 realpath()によるシンボリックリンクパス名の取得

```py
#リンクファイルの実態を取得する。
>>> os.path.realpath("jeepers.txt")
'/Users/practice/bin/oops.txt'

```

##10.1.11 removeによるファイルの削除

```py

>>> os.remove("oops.txt")
>>> os.path.exists("oops.txt")
False

```

#10.2 ディレクトリ

- ファイルはディレクトリの階層構造にある。こういったファイル、ディレクトリ全体のコンテナをファイルシステムという。

##10.2.1 mkdir()による作成

```py
>>> os.mkdir("poems")
>>> os.path.exists("poems")
True

```
##10.2.2 rmdir()による削除

```py

>>> os.rmdir("poems")
>>> os.path.exists("poems")
False

```

##10.2.3 listdir()による内容リストの作成

```py

>>> os.mkdir("poems")
>>> os.listdir("poems")
[]

#サブディレクトリ作成
>>> os.mkdir("poems/mcintyre")
>>> os.listdir("poems")
['mcintyre']

>>> fout=open("poems/mcintyre/the_good_man","wt")
>>> fout.write("""Cheerful and happy was his mood,
... He to the poor was kind and good,
... And he oft times did find them food,
... Also suppleis of coal and wood,
... """)
137
>>> fout.close()
>>> os.listdir("poems/mcintyre")
['the_good_man']

```
##10.2.4 chdir()によるカレントディレクトリの変更

- 別のディレクトリに移動できる。

```py

>>> import os
>>> os.chdir("poems")
>>> os.listdir(".")
['mcintyre']

```

##10.2.5 glob()によるパターンにマッチするファイルのリスト作成

- *は全てのものにマッチする。
- ?は任意の1文字にマッチする。
- [a,b,c]はa,b,cのどれかにマッチする。
- [!a,b,c]はa,b,c以外の文字にマッチする。

```py

>>> import glob
>>> glob.glob("m*")
['mcintyre']
>>> glob.glob("??")
[]
>>> glob.glob("m??????e")
['mcintyre']
>>> glob.glob("[klm]*e")
['mcintyre']

```

#10.3 プログラムとプロセス

- 個別のプログラムを実行すると、オペレーティングシステム(OS)は**プロセス**を一つ作る。
 - プロセスは独立しているし、覗いたり邪魔はできない。
 
- OSは実行されている全てのプロセスを管理している。
- プロセスデータにはプログラム自身からもアクセス可能→標準ライブラリのosモジュールを使う。

```py

>>> import os
#プロセスidを取得。
>>> os.getpid()
40037
#カレントディレクトリを取得。
>>> os.getcwd()
'/Users/practice/bin/poems'
#ユーザーid取得。
>>> os.getuid()
501
#グループid取得。
>>> os.getgid()
20

```

##10.3.1 subprocessによるプロセスの作成

- 標準ライブラリのsubprocessモジュールを使えば、Pythonから他の既存プログラムを起動、終了できる。

```py

>>> import subprocess
>>> ret=subprocess.getoutput("date")
>>> ret
'2020年 1月28日 火曜日 11時17分59秒 JST'
>>> ret=subprocess.getoutput("date -u")
>>> ret
'2020年 1月28日 火曜日 02時19分40秒 UTC'
>>> ret=subprocess.getoutput("date -u | wc")
>>> ret
'       1       5      48'

#コマンドと引数のリストを受け付ける。
>>> ret=subprocess.check_output(["date","-u"])
>>> ret
b'2020\xe5\xb9\xb4 1\xe6\x9c\x8828\xe6\x97\xa5 \xe7\x81\xab\xe6\x9b\x9c\xe6\x97\xa5 02\xe6\x99\x8222\xe5\x88\x8605\xe7\xa7\x92 UTC\n'

#ステータスコードと出力のタプルが返される。
>>> ret=subprocess.getstatusoutput("date")
>>> ret
(0, '2020年 1月28日 火曜日 11時26分35秒 JST')

#終了ステータスのみの受け取りはcall()を使う。
>>> ret=subprocess.call("date")
2020年 1月28日 火曜日 11時27分05秒 JST
>>> ret
0
>>> ret=subprocess.call("date -u",shell=True)
2020年 1月28日 火曜日 02時30分49秒 UTC
>>> ret=subprocess.call(["date", "-u"])
2020年 1月28日 火曜日 02時34分41秒 UTC

```

##10.3.2 multiprocessingによるプロセスの作成

- multiprocessingモジュールを使えば、Python関数を別個のプロセスとして実行する。一つのプログラムの中で複数の独立したプロセスを実行することさえできる。

```py:mp.py

import multiprocessing
import os

def do_this(what):
	whoami(what)

def whoami(what):
	print("Process %s says: %s" % (os.getpid(), what))

#Process()関数は新しいプロセスを起動し、targetで指定したものを、argsで指定した引数を代入して実行する。
#argsで引数をする際、最後にカンマを入れないと文字列として認識され、結果がおかしくなる。
if __name__ == "__main__":
	whoami("I'm the main program")
	for n in range(4):
		p = multiprocessing.Process(target=do_this, args=("I'm function %s" % n,))
		p.start()

```

```py:実行結果

python mp.py
Process 40422 says: I'm the main program
Process 40438 says: I'm function 0
Process 40439 says: I'm function 1
Process 40440 says: I'm function 2
Process 40441 says: I'm function 3

```

##10.3.3 terminate()によるプロセスの強制終了

```py:termina.py

import multiprocessing
import time
import os

def whoami(name):
	print("I'm %s, in process %s" % (name, os.getpid()))

def loopy(name):
	whoami(name)
	start = 1
	stop = 1000000
	for num in range(start, stop):
		print("\tNumber %s of %s. Honk!" % (num, stop))
		time.sleep(1)

if __name__ == '__main__':
	whoami("main")
	p = multiprocessing.Process(target=loopy, args=("loopy" ,))
	p.start()
	time.sleep(5)
	p.terminate()

```

```py:実行結果

python termina.py
I'm main, in process 40518
I'm loopy, in process 40534
	Number 1 of 1000000. Honk!
	Number 2 of 1000000. Honk!
	Number 3 of 1000000. Honk!
	Number 4 of 1000000. Honk!
	Number 5 of 1000000. Honk!

```

#10.4 カレンダーとクロック


```py

#うるう年かどうかテストする。
>>> import calendar
>>> calendar.isleap(1900)
False
>>> calendar.isleap(1996)
True
>>> calendar.isleap(1999)
False
>>> calendar.isleap(2000)
True
>>> calendar.isleap(2002)
False
>>> calendar.isleap(2004)
True

```

##10.4.1 datetimeモジュール

- datetimeモジュールには4個のメインオブジェクトを定義している。
 - 年月日を対象とするdate
 - 時分秒と端数を対象とするtime
 - 日付と時刻の両方を対象とするdatetime
 - 日付と時刻の間隔を対象とするtimedelta

```py

>>> from datetime import date
>>> halloween=date(2014,10,31)
>>> halloween
datetime.date(2014, 10, 31)

#属性として取り出すことができる。
>>> halloween.day
31
>>> halloween.month
10
>>> halloween.year
2014
#dateの内容はisformat()で表示できる。
>>> halloween.isoformat()
'2014-10-31'

#today()メソッドを使って今日の日付生成。
>>> from datetime import date
>>> now=date.today()
>>> now
datetime.date(2020, 1, 28)

>>> from datetime import timedelta
>>> one_day=timedelta(days=1)
>>> tomorrow=now + one_day
>>> tomorrow
datetime.date(2020, 1, 29)
>>> now + 17*one_day
datetime.date(2020, 2, 14)
>>> yesterday=now-one_day
>>> yesterday
datetime.date(2020, 1, 27)

#1日の中の時刻を表現するにはdatetimeモジュールのtimeオブジェクトを使う。
>>> from datetime import time
>>> noon=time(12,0,0)
>>> noon
datetime.time(12, 0)
>>> noon.hour
12
>>> noon.minute
0
>>> noon.second
0
>>> noon.microsecond
0

#datetimeオブジェクトもisoformat()メソッドを持っている。
>>> from datetime import datetime
>>> some_day=datetime(2014,1,2,3,4,5,6)
>>> some_day
datetime.datetime(2014, 1, 2, 3, 4, 5, 6)
>>> some_day.isoformat()
'2014-01-02T03:04:05.000006'

#datetimeは、現在の日付と時刻を取得するnow()メソッドを持っている。
>>> from datetime import datetime
>>> x=datetime.now()
>>> x
datetime.datetime(2020, 1, 28, 13, 59, 8, 731311)
>>> x.year
2020
>>> x.day
28
>>> x.hour
13
>>> x.minute
59
>>> x.second
8
>>> x.microsecond
731311

#combineを使えばdateとtimeオブジェクトを結合できる。
>>> from datetime import datetime,time,date
>>> noon=time(12)
>>> this_day=date.today()
>>> noon_today=datetime.combine(this_day,noon)
>>> noon_today
datetime.datetime(2020, 1, 28, 12, 0)
>>> noon_today.date()
datetime.date(2020, 1, 28)
>>> noon_today.time()
datetime.time(12, 0)

```

##10.4.2 timeモジュールの使い方

- datetimeモジュールのtimeオブジェクトの他にtimeモジュールがある。→timeモジュールのtime()関数はUnix時間を返す。

- Unix時間は1970年1月1日午前0時からの秒数を使っている。

```py

>>> import time
>>> now=time.time()
>>> now
1580188038.071847

#ctime()を使うとUnix時間を文字列に変換できる。
>>> time.ctime(now)
'Tue Jan 28 14:07:18 2020'

#localtime()はシステムでの標準時での日時を返す。
>>> time.localtime(now)
time.struct_time(tm_year=2020, tm_mon=1, tm_mday=28, tm_hour=14, tm_min=7, tm_sec=18, tm_wday=1, tm_yday=28, tm_isdst=0)

#gmttime()はUTCでの時刻を返す。
>>> time.gmtime(now)
time.struct_time(tm_year=2020, tm_mon=1, tm_mday=28, tm_hour=5, tm_min=7, tm_sec=18, tm_wday=1, tm_yday=28, tm_isdst=0)

#mktime()はstruct_timeオブジェクトをUnix時間に変換する。
>>> tm=time.localtime(now)
>>> time.mktime(tm)
1580188038.0

```

##10.4.3 日時の読み書き

- 日時の出力はisoformat()の専売特許ではない。
- strftime()はtimeモジュール、datetime,date,timeオブジェクトの関数として提供されており、文字列に変換できる。
- 文字列を日時情報に変換するにはstrptime()を使う。

```py

#ctime()はUnix時間を文字列に変換する。
>>> import time
>>> now=time.time()
>>> time.ctime(now)
'Tue Jan 28 14:15:57 2020'

>>> import time
#strftime()の書式指定子を使う。
>>> fmt="""It is %A,%B,%d,%Y, local time %I:%M:%S%p"""
>>> t=time.localtime()
>>> t
time.struct_time(tm_year=2020, tm_mon=1, tm_mday=28, tm_hour=14, tm_min=21, tm_sec=10, tm_wday=1, tm_yday=28, tm_isdst=0)
#struct_timeを文字列に変換する。
>>> time.strftime(fmt,t)
'It is Tuesday,January,28,2020, local time 02:21:10PM'


>>> from datetime import date
>>> some_day=date(2014,7,4)
#dateオブジェクトで使うと日付のみ整形される。
>>> some_day.strftime(fmt)
'It is Friday,July,04,2014, local time 12:00:00AM'

>>> from datetime import time
>>> some_time=time(10,45)
#timeオブジェクトで使うと時刻のみ整形される。
>>> some_time.strftime(fmt)
'It is Monday,January,01,1900, local time 10:45:00AM'

#逆に文字列を日時情報に変換するにはstrptime()を使う。
#書式子以外の部分は正確に一致していなければならない。
>>> import time
>>> fmt="%Y-%m-%d"
>>> time.strptime("2012-01-29",fmt)
time.struct_time(tm_year=2012, tm_mon=1, tm_mday=29, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=29, tm_isdst=-1)

#setlocale()を使うと指定したロケールで日付を返してくれる。
>>> import locale
>>> from datetime import date
>>> halloween=date(2014,10,31)
>>> for lang_country in ["en_us","fr_fr","de_de","es_es","is_is",]:
...     locale.setlocale(locale.LC_TIME,lang_country)
...     halloween.strftime("%A, %B, %d")
... 
'en_us'
'Friday, October, 31'
'fr_fr'
'Vendredi, octobre, 31'
'de_de'
'Freitag, Oktober, 31'
'es_es'
'viernes, octubre, 31'
'is_is'
'föstudagur, október, 31'

>>> import locale
>>> names=locale.locale_alias.keys()
>>> good_names=[name for name in names if
... len(name)==5 and name[2]=="_"
... 
... 
... ]
>>> good_names[5]
'ak_gh'
>>> good_names=[name for name in names if
... len(name)==5 and name[2]=="_"]
>>> good_names[5]
'ak_gh'
>>> good_names[:5]
['a3_az', 'aa_dj', 'aa_er', 'aa_et', 'af_za']
>>> de=[name for name in good_names if name.startswith("de")]
>>> de
['de_at', 'de_be', 'de_ch', 'de_de', 'de_it', 'de_lu']

```

#10.5 復習問題

##10-1 現在の日付をtoday.txtというテキストファイルに文字列の形で書き込もう。

```py

>>> from datetime import date
>>> with open("today.txt","wt") as fout:
...     now=date.today()
...     now_str=now.isoformat()
...     print(now_str,file=fout)

```

##10-2 テキストファイルtoday.txtの内容をtoday_stringという文字列変数に読み込もう。

```py

>>> with open("today.txt","rt") as input:
...     today_string=input.read()
... 
>>> today_string
'2020-01-28\n'

```

##10-3 today_stringから日付を解析して取り出そう。

```py

>>> import time
>>> fmt="%Y-%m-%d\n"
#文字列⇨日付情報にするにはstrptime()を使う。
>>> time.strptime(today_string,fmt)
time.struct_time(tm_year=2020, tm_mon=1, tm_mday=28, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=28, tm_isdst=-1)

```

##10-4 カレントディレクトリのファイルのリストを作ろう。

```py
>> import os
>>> os.listdir(".")
[`flask2.py`, `pip3.7`, `jeepers.txt`, `villains`, `activate.ps1`, `index.html`, `.DS_Store`, `python3`, `settings.cfg`, `relativity`, `yikes.txt`, `easy_install`, `python`, `pip3`, `ohwel.txt`, `today.txt`, `activate.fish`, `easy_install-3.7`, `bottle3.py`, `zoo.py`, `flask9-2.py`, `test1.py`, `weather.py`, `bottle2.py`, `wheel`, `enterprise.db`, `flask9-3.py`, `links.py`, `__pycache__`, `flask3a.py`, `python3.7`, `test2.py`, `bottle1.py`, `python-config`, `activate_this.py`, `pip`, `bottle_test.py`, `definitions.db`, `flask3b.py`, `menu.xml`, `books.csv`, `mp.py`, `activate.xsh`, `weatherman.py`, `lelatibity`, `termina.py`, `bfile`, `flask3c.py`, `relatibity`, `flask9-5.py`, `sources`, `text.txt`, `templates`, `activate`, `poems`, `books.db`, `flask1.py`, `mcintyre.yaml`, `report.py`, `zoo.db`, `activate.csh`]

```

##10-5 親ディレクトリのファイルのリストを作ろう。

```py

>>> import os
>>> os.listdir("..")
['.DS_Store', '61.py', 'bin', 'python', 'include', 'lib']


```

##10-6 multiprocessingを使って3個の別々のプロセスを作ろう。それぞれを1秒から5秒までのランダムな秒数だけ眠らせよう。

```py:multi_times.py

import multiprocessing
import os

def now(seconds):
    from datetime import datetime
    from time import sleep
    sleep(seconds)
    print("wait", seconds, "second, time is ", datetime.utcnow())

if __name__== "__main__":
    import random
    for n in range(3):
        seconds=random.random()
        proc=multiprocessing.Process(target=now, args=(seconds,))
        proc.start()

```

```py:実行結果

python3 multi_times.py
wait 0.31146317121366796 second, time is  2020-01-28 06:30:39.446188
wait 0.5162984978514253 second, time is  2020-01-28 06:30:39.650398
wait 0.8005158157521853 second, time is  2020-01-28 06:30:39.934936

```

##10-7 誕生日のdateオブジェクトを作ろう。

```py

>>> from datetime import date
>>> birthday=date(1994, 1, 1)
>>> birthday
datetime.date(1994, 1, 1)


```

##10-8 あなたの誕生日は何曜日だったか？

```py
>>> import time
>>> from datetime import date
>>> birthday=date(1994, 1, 1)
>>> fmt="%Y-%m-%d-%A"
>>> date.strftime(birthday,fmt)
'1994-01-01-Saturday'


```

##10-9 生まれてから10,000日になるのはいつか？

```py

>>> from datetime import timedelta
>>> day=timedelta(days=10000)
>>> A=birthday+day
>>> A
datetime.date(2021, 5, 19)


```

#感想

ささっと復習しました。
使う時にはチュートリアル等見ていきたいね。

######参考文献
「Bill Lubanovic著 『入門 Python3』(オライリージャパン発行)」