Pythonとは
プログラミング言語Pythonのことであり、Pythonのインタプリタと言うソフトウェアが、Python形式で書かれたソースコードを読み込んで命令を実行する。プログラミング言語ごとに得意不得意な分野はあるが、Pythonに関しては機械学習、Webスクレイピング、画像解析など多種多様な有効な用途に使われているプログラミング言語。Djangoなどのフレームワークも使えばWebアプリケーションも作成できる
本記事では
Pythonを体系的に学ぶことを目的にしている。
あまりにも基本的なことは時間節約のため記載しないが、明らかに忘れそうだけど大事なことはまとめ記事として記載する。また有用なソースコードもsampleとして記載したい。
リスト型
リストは複数の値を順に並べた値で、値をインデックスを基にして取り出すことができる。
リストのインデックスの数値は0..1..2..3..と0から始まるので最も左にあるものがインデックス0
基本構文
sample=['cat','dog','bird']
sample[1]
'dog'
sample=['cat','dog','bird','elephant']
sample[1:3]
['dog', 'bird']
sample=['cat','dog','bird','elephant']
len(sample)
4
sample=['cat','dog','bird','elephant']
sample[1]='Big Dog'
sample
['cat', 'Big Dog', 'bird', 'elephant']
sample=['cat','dog','bird','elephant']
del sample[2]
sample
['cat', 'dog', 'elephant']
メソッド
メソッドとはある値について呼び出される専用の関数。更新形関数(appned,remove,insert等)はspam=spam・・・と言う形で更新するのではなく、spam.関数()でspamを変更可能。こういった変更の仕方をインプレースと呼ぶ。
spam=['cat','dog','bat']
spam.append('moose')
spam
['cat', 'dog', 'bat', 'moose']
spam=['cat','dog','bat']
spam.insert(1,'moose')
spam
['cat', 'moose', 'dog', 'bat']
spam=['cat','dog','bat']
spam.remove('dog')
spam
['cat', 'bat']
# 削除する値が複数ある場合は、最初の値だけが削除される
# 数値の場合は、小さい値〜大きな値
spam=[2,5,3.14,1,-7]
spam.sort()
spam
[-7, 1, 2, 3.14, 5]
# 文字列の場合はA~Z,a~z順
spam=['cat','ant','Elephant','bat','Dog']
spam.sort()
spam
['Dog', 'Elephant', 'ant', 'bat', 'cat']
# 大文字も小文字も区別なくアルファベット順にsortしたい場合は,keyと言うキーワードにstr.lower指定。
これで全てを小文字とみなしてsort処理がされる
spam=['cat','ant','Elephant','bat','Dog']
spam.sort(key=srt.lower)
spam
['ant', 'bat', 'cat', 'Dog', 'Elephant']
# reverse=Trueを付与すると逆順になる
spam=[2,5,3.14,1,-7]
spam.sort(reverse=True)
spam
[5, 3.14, 2, 1, -7]
リストの値の数に関して
tips:常にリストの値の数を取得する方法としては下記のような書き方がある。
len([リスト])-1
タプル
リストとほぼ同じデータ型としてタプルというものがある。
タプルは2点を除いてリストと同じデータ型である。
(1)()で値を囲む
(2)タプルには値を変更したり、追加、削除したりすることはできない。
上記だけならばリストの方が完全に上位互換に見えるが、リストよりもメモリの消費が少ない、また確実に更新できないようにできる点を考えれば、タプルで済むものはタプルで構成する方が良い。
spam=('cat','dog','bat')
>>> spam=('cat','dog','bat')
>>> spam
('cat', 'dog', 'bat')
>>> spam[1]
'dog'
>>> spam.append('XXX')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'
>>> spam.insert('XXX',2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'insert'
>>> spam.remove('dog')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'remove'
参照
変数は、変数に値の実体を入れるが、リストはこの挙動が異なる。
リストは変数にあくまでリストの参照(ショートカット的なもの)を代入する。結果的に以下のような挙動になる。
リストでなければspamの値は不変でcheeseの値だけ変わるが、リストは変数に参照を代入しているだけなのでspamの値も変わるという挙動
>>> spam=[0,1,2,3]
>>> cheese=spam
>>> cheese[1]='Hello'
>>> spam
[0, 'Hello', 2, 3]
>>> cheese
[0, 'Hello', 2, 3]
変数代入の過程で参照を渡したくない場合は、copyモジュールを利用する必要がある。
通常のリストをコピーしたい場合は、copyメソッド。リストを含むリストをコピーする場合はdeepcopyメソッドを用いる。
import copy
spam=['cat','dog','bat']
cheese=copy.copy(spam)
cheese[1]=42
spam
['cat', 'dog', 'bat']
cheese
['cat', 42, 'bat']
辞書型
辞書はデータを編成して柔軟なアクセスを可能なデータ型である。リストと同様に多くの値の集合だが、リストのインデックスが整数型だったのに対して、辞書のインデックスは任意の値(任意のデータ型)を用いることができる。辞書のインデックスのことをキー、キーに対応する値の組みを「キーバリューペア」と呼称する。
my_cat={'size':999,'color':'Red'}
my_cat['size']
999
メソッド
1.辞書のキーやバリューを返してくれるメソッド
辞書にはリスト風の値を返すメソッドが3つ存在する。
keys・・・キーだけ表示
values・・・バリューだけ表示
items・・・キーバリューペアで表示
spam={'color':'red','age':42}
# リストで表示したい場合
spam.keys()
['color', 'age']
# 1つずつ改行して取り出したい場合
for k in spam.keys():
... print(k)
...
color
age
spam={'color':'red','age':42}
# リストで表示したい場合
spam.values()
['red', 42]
# 1つずつ改行して取り出したい場合
for v in spam.values():
... print(v)
...
red
42
spam={'color':'red','age':42}
# リストで表示したい場合
spam.items()
[('color', 'red'), ('age', 42)]
# 1つずつ改行して取り出したい場合
for k,v in spam.items():
... print('Key: ' + k + ' Value: ' + str(v))
...
Key: color Value: red
Key: age Value: 42
2.キーや値が辞書に含まれるかどうかの判定
spam={'color':'red','age':42}
### inを駆使してTrue/False判定する
'name' in spam.keys()
False
'red' in spam.values()
True
# keysもvaluesもつけない場合はkeys
'color' in spam
True
'red' in spam
False
3.便利な参照用・更新用メソッド
参照用
# キーがある場合はそのキーへアクセスし、無ければ代わりの値を表示するメソッド。
有無の分岐ハンドリングをプログラムでしなくて良い。
spam={'color':'red','age':42}
spam.get('color','black')
'red'
spam.get('colorx','black')
'black'
更新用
# キーが未登録の場合のみ値を登録して、登録済みの場合は何もしないメソッド。
どちらにしてもバリューの値を返す
spam={'color':'red','age':42}
# 登録済みの場合
spam.setdefault('color','black')
'red'
# 未登録の場合
spam.setdefault('colorx','black')
'black'
spam
{'color': 'red', 'colorx': 'black', 'age': 42}
参考:ドローイングツール
https://www.draw.io/
文字列操作系各種メソッド
python言語で文字列を操作できるメソッドについて備忘としておまとめ記載。
# 元の文字列を全て大文字で表示
spam='Hello World'
spam.upper()
'HELLO WORLD'
# 元の文字列を全て小文字で表示
spam='Hello World'
spam.lower()
'hello world'
# 元の文字列を全て大文字であればTRUE、そうでなければFALSEを返す
spam1='Hello World'
spam1.isupper()
False
spam2='HELLO WORLD'
spam2.isupper()
True
# 元の文字列を全て大文字であればTRUE、そうでなければFALSEを返す
spam1='Hello World'
spam1.islower()
False
spam2='hello world'
spam2.islower()
True
# 1文字以上の英文字だけから文字列が構成されていればTRUE、そうでなければFALSE
spam='aaaaa'
spam.isalpha()
True
spam='aaaaa1'
spam.isalpha()
False
# 1文字以上の英文字か数字だけから文字列が構成されていればTRUE、そうでなければFALSE
spam='aaaaa1'
spam.isalnum()
True
spam='aaaaa1zz$'
spam.isalnum()
False
# 1文字以上の数字だけから文字列が構成されていればTRUE、そうでなければFALSE
spam='123456'
spam.isdigit()
True
spam='123456ZZZ'
spam.isdigit()
False
# 1文字以上の数字だけから文字列が構成されていればTRUE、そうでなければFALSE
spam='123456'
spam.isdecimal()
True
spam='123456ZZZ'
spam.isdecimal()
False
# 文字列がスペースかタブか改行だけから構成されていればTRUE、そうでなければFALSE
spam=' '
spam.isspace()
True
spam=' z'
spam.isspace()
False
# 大文字から始まり残りすべてが小文字の英単語から構成されていればTRUE、そうでなければFALSE
spam='This Is A Pen'
spam.istitle()
True
spam='This is a pen'
spam.istitle()
False
# 対象の文字列がメソッドに渡された文字列から始まる場合はTRUE、そうでなければFALSE。
大文字小文字は区別する。
spam='Test Message'
spam.startswith('Test')
True
spam.startswith('test')
False
# 対象の文字列がメソッドに渡された文字列で終わる場合はTRUE、そうでなければFALSE。
大文字小文字は区別する。
spam='Test Message'
spam.endswith('Message')
True
spam.endswith('message')
False
# 対象の文字列がメソッドに渡された文字列をいくつ含むかを返す
spam='Test Test Test Messages'
spam.count('Test')
3
# 指定した文字列の最初の出現箇所を返す。存在しない場合は-1を返す
spam='XYZ Test Messages'
spam.find('Test')
4
spam.find('ABC')
-1
# 指定した文字列の最初の出現箇所を返す。存在しない場合はエラーを返す
spam='XYZ Test Messages'
spam.index('Test')
4
spam.index('ABC')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
# 文字列oldをnewに置換する。countは置換の最大回数。デフォルト-1の時は全部置換
replace(old,new,count=-1)
spam='Test Messsage'
spam.replace('Test','XYZ')
'XYZ Messsage'
spam='Test Test Test Messages'
spam.replace('Test','XYZ',2)
'XYZ XYZ Test Messages'
# sepを区切るための文字列として、リストに分割(リスト化する)。最大分割数はmaxsplit。maxsplitが-1のときは全て分割
split(sep=None, maxsplit=-1)
'1 2 3'.split(' ')
['1', '2', '3']
# 改行文字を区切り文字としてリストに分割を実施する。
"""AAA
... BBB
... CCC""".splitlines()
['AAA', 'BBB', 'CCC']
# 文字列の先頭または末尾にメソッドに指定したcharsがあれば削除して値を返す。charsがしていない場合は空白文字が採用される
strip(chars=None)
spam='---AAABBBCCC---'
spam.strip('-')
'AAABBBCCC'
# 文字列の先頭にメソッドに指定したcharsがあれば削除して値を返す。charsがしていない場合は空白文字が採用される
lstrip(chars=None)
spam='---AAABBBCCC---'
spam.lstrip('-')
'AAABBBCCC---'
# 文字列の末尾にメソッドに指定したcharsがあれば削除して値を返す。charsがしていない場合は空白文字が採用される
rstrip(chars=None)
spam='---AAABBBCCC---'
spam.rstrip('-')
'---AAABBBCCC'
# 指定した文字数分を埋めるように、メソッドに指定した文字列を中央にしてその左右を引数に指定した文字で埋める
s='Hello'
s.center(20,'X')
'XXXXXXXHelloXXXXXXXX'
# 指定した文字数分を埋めるように、メソッドに指定した文字列を左にしてその右を全て引数に指定した文字で埋める
s='Hello'
s.ljust(20,'X')
'HelloXXXXXXXXXXXXXXX'
# 指定した文字数分を埋めるように、メソッドに指定した文字列を右にしてその左を全て引数に指定した文字で埋める
s='Hello'
s.rjust(20,'X')
'XXXXXXXXXXXXXXXHello'
# 指定した文字数分を埋めるように、メソッドに指定した文字列を右にしてその左を全て0で埋める
s='123456'
s.zfill(20)
'00000000000000123456'
ローカル変数とグローバル変数
Python プログラム内で使われる変数はローカル変数。その他関数外で使われる変数は、俗にグローバル変数という。
- ローカル変数は特定の関数内でのみ有効になる変数で、関数外で使おうとしても機能しない。
- グローバル変数はプログラム全体で使える変数で、全ての関数内で利用できる。
- 関数外で同じ変数名が使われている場合、関数内ではローカル変数が有効に、関数外ではグローバル変数が有効。
- 関数内でグローバル変数を定義する際は、global 句をつける。
def spam():
ham=999
spam()
print(ham)
Traceback (most recent call last):
File "<pyshell#85>", line 1, in <module>
ham
NameError: name 'ham' is not defined
ログ出力
logging モジュールを使用することで Python におけるログ出力を最適化することができる。
具体的には、ログレベルの定義してそのログの種別を定義したり、ログ形式を定義して例えば日時を自動で出すことが出来たりして便利。
ログファイルに対して、出力するようにするには以下のコード例のように書けば良い。
import logging
logging.basicConfig(filename='/tmp/example1.log',level=logging.DEBUG,format=" %(asctime)s - %(levelname)s - %(message)s")
logging.debug('This message should go to the log file')
# ログ出力例
$ cat example1.log
2020-04-25 21:06:32,050 - DEBUG - This message should go to the log file
ログレベルの優先順位は以下の通り。定義したログレベル以上のログがログ出力される
DEBUG < INFO < WARNING < ERROR < CRITICAL
コピー&ペースト
pyperclipモジュールにてPythonでコピー&ペーストを実施する。
pyperclipモジュールにはcopy()とpaset()というメソッドがあり、PCのクリップボードとテキストを授受することが可能である。例えばプログラムの出力を自動的にクリップボードに送ることが出来れば貼り付け作業が簡易的になる。copy()はクリップボードへのコピー(Ctrl+C)と同義、paste()は貼り付け処理(Ctrl+V)と同義。
import pyperclip
pyperclip.copy('hello world')
pyperclip.paste()
'hello world'
日付関係
Pythonにはdatetimeモジュールに日付と時間を扱う型(クラス)がある。
datetimeモジュールの主な型
date: 年月日の日付を扱う(日付型)
time: 時分秒、マイクロ秒の時刻を扱う(時刻型)
datetime: 日付、時刻の両方を扱う(日付時刻型)
timedelta: 日付、時刻の間隔を扱う
date型
作成方法と主なクラスメソッド | 説明 |
---|---|
date(year, month, day) | 引数で指定される日付を作成します(存在しない場合ValueError) |
date.today() | 現在の日付を返します。 |
from datetime import date
>>> dt=date(2019,6,7)
>>> print(dt)
2019-06-07
>>> print(dt.weekday())
4
>>> print(dt.year)
2019
>>> print(dt.month)
6
>>> print(dt.day)
7
>>> print(f'{dt:%Y/%m/%d}')
2019/06/07
>>> print(dt.today())
2019-07-24
time型
作成方法と主なクラスメソッド | 説明 |
---|---|
time(hour, minute, second) | 引数で指定される時刻を作成します(存在しない場合ValueError)。 |
>>> from datetime import time
>>> tm=time(23,45,59)
>>> print(tm)
23:45:59
>>> print(tm)
23:45:59
>>> print(tm.hour)
23
>>> print(tm.minute)
45
>>> print(tm.second)
59
>>> print(f'{tm:%H:%M:%S}')
23:45:59
datetime型
作成方法と主なクラスメソッド | 説明 |
---|---|
datetime(year, month, day, hour, minute, second) | 引数で指定される日付時刻を作成します(存在しない場合ValueError)。 |
datetime.now() | 現在の日付時刻を取得 |
datetime.combine(date,time)) | 日付と時刻から日付時刻を作成 |
datetime.strptime(date_string, format) | formatを基準に、date_stringから日付時刻を作成します。 |
>>> from datetime import datetime
>>> dt = datetime(2019, 6, 7, 23, 45, 59)
>>> print(dt.date())
2019-06-07
>>> print(dt.time())
23:45:59
>>> print(datetime.now())
2019-07-24 22:26:16.088734
>>> print(dt)
2019-06-07 23:45:59
>>> print(f'{dt:%Y/%m/%d %H:%M:%S}')
2019/06/07 23:45:59
timedelta型
日付や時刻の加算、減算などを行うための型
timedelta(days=X,hours=X,minitus=X,seconds=X)
days 日数
hours 時間
minutes 分
seconds 秒
>>> from datetime import timedelta,datetime
>>> now=datetime.now()
>>> print(now)
2019-07-25 01:23:35.805321
>>> dt=timedelta(days=1,hours=1,minutes=20,seconds=30)
>>> print(now-dt)
2019-07-24 00:03:05.805321
ファイル入出力
Python経由でファイルに読み書きする方法を例示する。
本来的にはopenしたファイルは明示的にcloseしなければファイルディスクリプタが残ってしまうが、
下記のようにwith open文で記載することでcloseが自動的にされる。
[root@ro py]# cat example.csv
4/5/2014 13:34,Apples,73
4/5/2014 3:41,Cherries,85
4/6/2014 12:46,Pears,14
4/8/2014 8:59,Oranges,52
4/10/2014 2:07,Apples,152
4/10/2014 18:10,Bananas,23
4/10/2014 2:40,Strawberries,98
>>> with open('example.csv','r',encoding='utf-8') as fp:
... for s in fp.readlines():
... print(s,end='')
...
4/5/2014 13:34,Apples,73
4/5/2014 3:41,Cherries,85
4/6/2014 12:46,Pears,14
4/8/2014 8:59,Oranges,52
4/10/2014 2:07,Apples,152
4/10/2014 18:10,Bananas,23
4/10/2014 2:40,Strawberries,98
>>> with open('sample.txt','w',encoding='utf-8') as fp:
... fp.write('今日の天気は')
...
6
>>> # ファイルの追記
... with open('sample.txt','a',encoding='utf-8') as fp:
... fp.write('晴れです\n')
... fp.write('午後からは曇りになります\n')
...
5
13
>>> with open('sample.txt','r',encoding='utf-8') as fp:
... for s in fp.readlines():
... print(s,end='')
...
今日の天気は晴れです
午後からは曇りになります
ランダム文字列生成
テストデータなど作りたいときにランダム文字列を任意の文字数で作りたかったので
方法を調べた。結論的にpython3.6以降はrandomモジュールを利用する。
import random
import string
# ascii文字列で生成する場合
>>> ''.join(random.choices(string.ascii_letters, k=5))
'uMOyB'
# 数字文字列で生成する場合
>>> ''.join(random.choices(string.digits, k=8))
'80813027'
# asciiと数字で生成する場合
>>> ''.join(random.choices(string.ascii_letters + string.digits, k=20))
'MOMCT9giPBYNWNZT0kcJ'
# 指定した範囲の乱数を取得する方法
>>> random.uniform(1,1000)
691.4786809502596
>>> random.uniform(1,1000)
589.7376804112627
# 指定した範囲の整数の乱数を取得する方法
>>> random.randint(1,1000)
232
>>> random.randint(1,1000)
901
# 配列の中身をランダムに取得する方法
>>> a=['spam','burger','hoge']
>>> random.choice(a)
'spam'
>>> random.choice(a)
'burger'
>>> random.choice(a)
'burger'
------------------------
補足:stringモジュールの関数でアルファベットや数字という概念を定義可能。
これを応用してランダム文字列を生成
string.ascii_letters ascii_lowercaseとascii_uppercaseを合わせたもの
string.ascii_lowercase アルファベット小文字
string.ascii_uppercase アルファベット大文字
string.digits 数字(0~9)
CSV 作成処理
DB に大量のテストデータを作成したいときに簡単にテスト用の CSV データを作れると非常に便利である。
以下 Python で簡単にランダムなテストデータを作成する際の例。csv モジュールを利用。
import random
import csv
import string
import time
# テスト CSV データ作成 1億行
start=time.time()
with open('/tmp/bigdata.csv','w', encoding="utf-8") as f:
writer = csv.writer(f,delimiter=',')
for i in range(100000000):
id=i+1
col1=random.randint(1,1000)
col2=''.join(random.choices(string.ascii_letters, k=5))
col3=''.join(random.choices(string.ascii_letters + string.digits, k=100))
row=[id,col1,col2,col3]
writer.writerow(row)
end=time.time()
print(round(end-start,2))
例外処理
例外処理することで、発生したエラーに応じた処理を書くことが可能である。
pythonでは基本try~except文で書く。
また必ず処理を行うfinally文をつけたり、明示的にraise文で例外をあげることも可能。
例えば下記はリストにないIndexを指定してIndexErrorを例外として拾っている。
num_list = [1, 2, 3, 4, 5]
try:
num_list[10]
print('上で例外が起きたので、この部分は表示されない')
except IndexError:
print('IndexError: リストに存在しない要素が参照されました')
else:
print('その他のエラーです')
finally:
print('例外文を終了')
基本的なOS操作
Pythonでの基本的なOS操作(ファイル、フォルダ操作)の方法を記載する。
import shutil,os
# /tmpへカレントディレクトリ移動
os.chdir('/tmp')
os.getcwd()
'/tmp'
# ファイルコピー
shutil.copy('testfile1','testfile2')
'testfile2'
# フォルダコピー
shutil.copytree('aaadir','bbbdir')
'bbbdir'
# ファイル・フォルダ移動、リネーム
shutil.move('testfile2','testfile3')
'testfile3'
# ファイル削除
os.unlink('削除ファイル名')
# フォルダ削除(中身は空でなければならない)
os.rmdir('削除フォルダ名')
# フォルダ削除(中身は空である必要なく再帰的)
shutil.rmtree('削除フォルダ名')
# 指定パス以下のファイル、ディレクトリの一覧
os.listdir('パス')
# ファイルかどうかの判定。ディレクトリかどうかの判定。工夫すればファイルだけ、ディレクトリだけ削除のようなことが可能。正しければTRUE。BOOLEAN型
os.path.isfile('パス')
os.path.isdir('パス')
# ファイルであれ、ディレクトリであれ存在するかどうかの判定
os.path.exists('パス')
Webスクレイピング
プログラムを使ってWebコンテンツをダウンロードして処理すること。
スクレイピングをするのに役立つモジュールとしては下記のようなものがある。
# 指定したページをwebブラウザで開く
>>> import webbrowser
>>> webbrowser.open('開きたいURL')
True
# webページからファイルやHTMLのダウンロードを実施する
import requests
# resにHTMLの内容を保存
res=requests.get('https://automatetheboringstuff.com/files/rj.txt')
# HTTPステータスコードを検査
>>> res.status_code == requests.codes.ok
True
# ダウンロードしたHTMLをファイルへ保存する。バイナリ書き込みモードで保存する必要がある。
>>> with open('sample.txt','wb') as fp:
... for chunk in res.iter_content(100000):
... fp.write(chunk)
...
100000
78978
AWS S3をfindするためのPythonスクリプト
# !/usr/bin/python
import os
import sys
import boto3
import datetime
# args
AWS_S3_BUCKET_NAME = sys.argv[1]
PREFIX = sys.argv[2]
s3 = boto3.resource('s3')
bucket = s3.Bucket(AWS_S3_BUCKET_NAME)
os.unlink('/tmp/sample.csv')
with open('/tmp/sample.csv','a') as fp:
for i in bucket.objects.filter(Prefix=PREFIX):
fp.write(i.key + ',' + str(i.last_modified) + '\n')
dt=datetime.datetime.strptime(utc_date_str, '%Y-%m-%d %H:%M:%S')
print(dt.year)
dt=datetime.datetime.now()
print(dt)