Flat Leon Works

アプリやゲームを作ってます。

【Python】個人的逆引きリファレンス

Pythonでの個人的によく書くコードを逆引きリファレンスとしてまとめておこうと思います。(随時更新)

注意:

  • Python2.7を対象としてます
  • Pythonに詳しいわけではないので変な書き方をしているかもしれません
  • 動作確認してません

言語機能

for文でインデックスも利用する : for i, v in enumerate( hoge ):

strList = ['ne', 'ushi', 'tora']
for i, v in enumerate( strList ):
    print( 'Index: {}, value: {}'.format( i, v ) )

ドキュメント :
enumerate(組み込み関数)

2つのリストをfor文で走査する : for (a, b) in zip( listA, listB ):

for (a, b) in zip('abc', '12345'):
    print( '{}:{}'.format( a, b ) )

出力

a:1
b:2
c:3

ドキュメント :
zip(組み込み関数)

辞書

ドキュメント :
マッピング型

辞書を作成する : {key:value}

a = {'one': 1, 'two': 2, 'three': 3} # 一般的な方法
b = dict(one=1, two=2, three=3) # dictコンストラクタでキーワード引数
c = dict([('two', 2), ('one', 1), ('three', 3)]) # 2要素iterable(これがキーと値になる)のiterableを渡して作成
assert( a == b == c )

空辞書を作成する : {}

{} # 空辞書を作成
dict() # これも空の辞書

項目数を取得する : len(dictObj)

print( len( {'apple':100,'orange':200} ) ) # 2

キーが存在するかどうかを取得する : key in dictObj

dictObj = {'apple':100,'orange':200}
print( 'banana' in dictObj ) # False

キーに対応する値を取得する : dictObj.get( key )

dictObj = {'apple':100,'orange':200}
print( dictObj.get( 'orange' ) ) # 200
print( dictObj.get( 'banana' ) ) # None

# キーが存在しない場合の値を設定することもできる(設定しない場合はNoneになる)
print( dictObj.get( 'apple', 400 ) ) # 100
print( dictObj.get( 'banana', 400 ) ) # 400

# []でのアクセスだとキーが存在しない場合、KeyErrorが発生してしまう
# print( dictObj['banana'] ) 

ドキュメント :
dict.get

キーに対応する値を設定する : dictObj[key] = value

dictObj = {'apple':100,'orange':200}
dictObj['banana'] = 400

キーが存在しない場合のみキーに対応する値を設定する : dictObj.setdefault( key, value )

setdefaultメソッドはキーが存在しない場合に値をセットします。戻り値は最終的なキーに対応する値です。

dictObj = {'apple':100,'orange':200}
print( dictObj.setdefault( 'apple', 400 ) ) # 100
print( dictObj.setdefault( 'banana', 400 ) ) # 400

ドキュメント :
dict.setdefault

項目を削除する : dictObj.pop( key )

popメソッドはkeyを削除しその値を返します。del文でも項目を削除できますが、KeyErrorの発生を回避できるpopメソッドの方が良さそうです。

dictObj = {'apple':100,'orange':200}
print( dictObj.pop( 'apple' ) ) # 100

# キーが存在しなかった場合KeyErrorが発生してしまうが、デフォルト値を渡すことで回避できる
print( dictObj.pop( 'banana' ) ) # KeyErrorが発生してしまう
print( dictObj.pop( 'banana', None ) ) # None

# del文でも項目を削除できるが、キーが存在しなかった場合KeyErrorが発生してしまう
del dictObj['apple']

ドキュメント :
dict.pop

すべての項目を削除する : dictObj.clear()

dictObj = {'apple':100,'orange':200}
dictObj.clear()

ドキュメント :
dict.clear

項目(key,value)のリストを取得する : dictObj.items()

dictObj = {'apple':100,'orange':200}
print( dictObj.items() ) # [('orange', 200), ('apple', 100)]

ドキュメント :
dict.items

キーのリストを取得する : dictObj.keys()

dictObj = {'apple':100,'orange':200}
print( dictObj.keys() ) # ['orange', 'apple']

ドキュメント :
dict.keys

値のリストを取得する : dictObj.values()

dictObj = {'apple':100,'orange':200}
print( dictObj.values() ) # [200, 100]

ドキュメント :
dict.values

数値

ランダムな値を取得

print( random.randrange( 10 ) ) # 0〜9のランダムな数値
print( random.randrange( 1, 11 ) ) # 1〜10のランダムな数値

ドキュメント :
random.randrange
range

文字列

ドキュメント :
文字列メソッド
シーケンス型メソッド

整数を文字列化

# 普通に文字列化
print( str(10) ) # 10

# 16進数
print( hex(10) ) # 0xa

# 書式で文字列化
print( '{:x}'.format( 10 ) ) # a
print( '{:X}'.format( 10 ) ) # A
print( '{:02x}'.format( 10 ) ) # 0a
print( '{:04X}'.format( 10 ) ) # 000A

書式を利用する

'{hoge}'.format( hoge='aaa' )

ドキュメント :
書式指定文字列の文法
文字列フォーマット操作 : %を使った古い方法

2つの文字列の先頭からの文字の一致数を数える

def GetMatchLength( str1, str2 ):
    ret = 0
    for (c1, c2) in zip(str1, str2):
        if c1 == c2: ret += 1
        else: break
    return ret
 
print( GetMatchLength( 'abc123', 'abcdef' ) ) # 3

ユニコード(UTF-8)

ドキュメント :
Unicode HOWTO — Python 2.7.14 ドキュメント

ソースファイルの文字コードを明記する

# -*- coding: utf-8 -*-

# ↑をファイルの最初の行(もしくは2行目)に記述する

これを行わないと、u""による文字列リテラルが正しく解釈されない。

ドキュメント :
PEP 263 -- Defining Python Source Code Encodings | Python.org

標準入出力でUTF-8を利用できるようにする

import sys
import codecs
 
sys.stdout = codecs.getwriter('utf_8')(sys.stdout)
sys.stderr = codecs.getwriter('utf_8')(sys.stderr)

ドキュメント :
codecs.getreader

str型をunicode型に変換する

str_text = 'あいうえお'
unicode_text = unicode( str_text, 'utf_8' )

ドキュメント :
unicode(標準関数)

unicode型をstr型に変換する

unicode_text = u'あいうえお'
str_text = unicode_text.encode('utf-8') 
print( type(str_text) ) # <type 'str'>

ドキュメント :
str.encode
ユニコード型

ユニコードの正規化を行う

import unicodedata

unicodedata.normalize("NFC", unicode_text )

ユニコード文字列は同じ文字でも複数の内部表現ができる場合があります。このような場合、Pythonは見た目上全く同じ文字列でも内部表現の違いで別の文字列と判断してしまいます。これを避けるためにはユニコード文字列に対して正規化という処理を施し、内部表現に違いがでないようにします。ユニコードの内部表現の違いが現れる場面としては、Mac上のファイル名を扱うときがあります。Macファイルシステムは日本語の濁点が付いた文字を2つの文字(コードポイント)で表す方式(NFD)を採用していますが、この方式は一般的ではないので、見た目が同じで内部表現が違う文字列というのが出てきてしまいます。なので、Mac上のファイル名を取得した場合は、一般的なNFC方式に正規化してから扱う方がいいかもしれません。ちなみに、NFKC方式でも濁点問題を解決できますが、半角カナが全角カナにされてしまうことに注意が必要です。

ドキュメント :
unicodedata.normalize

参考 :
Unicode正規化

正規表現

正規表現で検索

import re
     
p = re.compile('.*\[(.*)\].*')
m = re.match( p, 'aiueo[hahaha]' )
print( m.group( 1 ) ) # hahaha

ドキュメント :
正規表現 HOWTO

正規表現で検索して置換

import re
     
# subで置換する方法
p = re.compile('\[(.*)\]')
print( re.sub( p, 'ehehe', '123[ohoho]456' ) ) # 123ehehe456

# splitで分割したものを操作し結合(join)する方法
p = re.compile('\[(.*)\]')
mlist = re.split( p, '123[ohoho]456' )
mlist[1] = '___'
print( ''.join( mlist ) ) # 123___456

ドキュメント :
正規表現 HOWTO

ファイル

ファイルの存在チェック : os.path.exists( path )

import os.path
if os.path.exists( path ):
    pass

ドキュメント :
os.path.exists

ファイル読み込み

import os.path

if os.path.exists( path ):
    with open( path, 'r' ) as openFile:
        fileData = openFile.read()

もしくは

import os.path
import codecs

if os.path.exists( path ):
    with codecs.open( path, 'r', 'utf_8' ) as openFile:
        fileData = openFile.read()

ドキュメント :
open
codecs.open

ファイル書き込み : with open( filePath, 'w' ) as openFile: openFile.write( writeData )

with open( filePath, 'w' ) as openFile:
    openFile.write( writeData )

もしくは

import codecs
with codecs.open( filePath, 'w', 'utf_8' ) as openFile:
    openFile.write( writeData )

ドキュメント :
file.write

ファイル削除 : os.remove( path )

import os
os.remove( path )

ドキュメント :
os.remove

ファイルコピー : shutil.copy2( src, dst )

import shutil
shutil.copy2( src, dst )
shutil.copy( src, dst ) # メタデータ(ファイル作成日など)をコピーしたくない場合はこっちを使う

ドキュメント :
shutil.copy2 shutil.copy

ファイル名変更 : os.rename( src, dst )

import os
os.rename( src, dst )

srcはディレクトリでも可。

ドキュメント :
os.rename

ファイル移動 : shutil.move( src, dst )

import shutil
shutil.move( src, dst )

srcはディレクトリでも可。

動作的には、srcとdstが同じファイルシステムならos.renameを実行するのみ、別のファイルシステムならファイルをコピー後、srcを削除するらしい。

ドキュメント :
shutil.move

ファイル更新日取得 : os.stat( path ).st_mtime

import os
os.stat( path ).st_mtime
# os.stat( path )[ST_MTIME] でもアクセス可能

ドキュメント :
os.stat

ファイル更新日変更 : os.utime( path, (atime, mtime) )

import os
settime = time.localtime()
os.utime( path, (settime, settime) ) # 引数として(最終アクセス時刻,最終更新時刻)のタプルを与える
# os.utime( path, None ) # Noneを与えた場合、現在時刻がセットされる

ドキュメント :
os.utime

指定のディレクトリ内のファイルリストを取得 : os.listdir( path )

import os
fileList = [os.path.join( path, i ) for i in os.listdir( path ) if os.path.isfile( os.path.join( path, i ) )]

os.listdirはファイル名(エントリ名)のみのリストを返すので、パスをくっつけている。また、os.listdirはファイルだけでなくディレクトリもリストに含めてしまうのでそれらは取り除いている。

ドキュメント :
os.listdir

指定のディレクトリ内のファイルを再帰的に走査する : os.walk( path )

走査してファイルリストを作成する例

import os

fileList = []
for dirpath, dirnames, filenames in os.walk( path ):
    fileList += [os.path.join( dirpath, i ) for i in filenames]

注意: 走査中はカレントディレクトリを変更してはいけない(byドキュメント)

ドキュメント :
os.walk

ディレクト

ディレクトリ作成 : os.mkdir( path )

import os
os.mkdir( path )

ドキュメント :
os.mkdir

ディレクトリ作成( 中間ディレクトリも作成 ) : os.makedirs( path )

import os
os.makedirs( path )

ドキュメント :
os.makedirs

ディレクトリ削除 : shutil.rmtree( path )

import shutil
shutil.rmtree( path )

ドキュメント :
shutil.rmtree

カレントディレクトリの取得 : os.getcwd()

import os
os.getcwd()

ドキュメント :
os.getcwd

カレントディレクトリの変更 : os.chdir( path )

import os
os.chdir( path )

ドキュメント :
os.chdir

パス操作

パスをつなげる : os.path.join( 'aaa', 'bbb' )

基本的に普通に文字列の+でも問題ないけど、os.path.joinの方が少しだけうまくやってくれる

import os.path
os.path.join( 'aaa', 'bbb' )  # aaa/bbb
os.path.join( 'aaa/', 'bbb' ) # aaa/bbb

ドキュメント :
os.path.join

ファイルパスから絶対パスを取得する : os.path.abspath( path )

import os.path
os.path.abspath( path )

ドキュメント :
os.path.abspath

ファイルパスからファイル名(拡張子付き)を取得する : os.path.basename( path )

import os.path
os.path.basename( path )

ドキュメント :
os.path.basename

ファイルパスからファイル名(拡張子なし)を取得する

import os.path

fileName = ''
if os.path.isdir( path ):
    fileName = os.path.basename( path )
else:
    fileName = os.path.splitext( os.path.basename( path ) )[0]

ドキュメント :
os.path.basename
os.path.splitext

ファイルパスからディレクトリ名を取得する

import os.path
dirName = ''
if os.path.isdir( path ):
    dirName = os.path.basename( path )
else:
    dirName = os.path.basename( os.path.dirname( path ) )

ファイルパスからディレクトリパスを取得する : os.path.dirname( path )

import os.path
os.path.dirname( path ) # pathはファイルパスを想定

ドキュメント :
os.path.dirname

ファイルパスから拡張子を取得する : os.path.splitext( path )[1]

import os.path
os.path.splitext( path )[1] # `.txt`など

ドキュメント :
os.path.splitext

ファイルパスがディレクトリを指しているかどうかを取得する : os.path.isdir( path )

import os.path
os.path.isdir( path )

ドキュメント :
os.path.isdir

日付と時間

現在時刻(datetime)を取得 : datetime.datetime.now()

import datetime

currentTime = datetime.datetime.now()

ドキュメント :
datetime.datetime.now

日時(datetime)を秒数に変換

(hogeDateTime - datetime.datetime.min).total_seconds()

文字列から日時(datetime)を作成 : datetime.datetime.strptime( dateStr, '%Y/%m/%d' )

import datetime
     
dateStr = '2017/11/20'
dateTime = datetime.datetime.strptime( dateStr, '%Y/%m/%d' )

ドキュメント :
datetime.datetime.strptime

日時(datetime)を文字列化 : datetime.strftime( '%Y/%m/%d' )

import datetime
     
nowDateTime = datetime.datetime.now()
dateStr = nowDateTime.strftime( '%Y/%m/%d' )

ドキュメント :
datetime.datetime.strftime

電子メールやHTTPの日付文字列(RFC 2822 形式)の変換

import email.utils

# 日付文字列から時間(秒)へ変換
timeValue = email.utils.mktime_tz( email.utils.parsedate_tz( 'Mon, 13 Nov 2017 01:23:45 -0000' ) )

# 時間(秒)から日付文字列へ変換
timeStr = email.utils.formatdate( timeValue )

ドキュメント :
email.utils

外部コマンドを実行 : subprocess.call( commandList )

import subprocess
subprocess.call( commandList )

ドキュメント :
subprocess.call

外部コマンドを実行(標準出力は表示しない)

外部コマンドの標準出力を表示しないようにしつつ、標準出力の内容を取得できる

p = subprocess.Popen( commandList, stdout=subprocess.PIPE )
(stdoutStr, stderrStr) = p.communicate()

ドキュメント :
subprocess.Popen

環境変数の取得 : os.environ['PATH']

import os
os.environ['PATH']

ドキュメント :
os.environ

例外

ドキュメント :
エラーと例外

例外を捉える

import sys

try: # 例外処理対象となる節
    pass
except ErrorA: # 特定の例外をキャッチ
    pass
except (ErrorB, ErrorC): # 複数の例外をキャッチ
    pass
except ErrorD as e: # 特定の例外をキャッチ( そして例外インスタンスを変数で受け取る )
    pass
except ErrorF, e: # except ErrorF as e:と同義。(古い文法であり後方互換のための記法)
    pass
except: # その他の例外をキャッチ
    print "Unexpected error:", sys.exc_info()[0] # sys.exc_info()はタプルで中身は(例外の型, 例外の引数, トレースバック)です
    raise # 例外を再送出
else: # 例外が発生しなかった場合に実行される節(省略可能)
    pass
finally: # 例外発生の有無によらず必ず最後に実行される節(省略可能)
    pass

ドキュメント :
例外を処理する

例外を発生させる

try:
    raise NameError( 'ahaha' ) # 例外を発生させる
except NameError:
    raise # 例外を再送出する

ドキュメント :
例外を送出する

捕捉されなかった例外を捉える : sys.excepthook

import sys
def my_except_hook(exctype, value, traceback):
    print( 'Exception! Yeah!:{}'.format( exctype ) )
    sys.__excepthook__(exctype, value, traceback)
sys.excepthook = my_except_hook
 
print( 'hoge' + 5 ) # 例外が発生

出力

標準出力
Exception! Yeah!:<type 'exceptions.TypeError'>

標準エラー
Traceback (most recent call last):
  File "prog.py", line 7, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

ドキュメント :
sys.excepthook

参考 :
Python Global Exception Handling - Stack Overflow

デバッグ(pdb)

デバッガ付きで実行する : python -m pdb ファイル名.py

スクリプトの実行時に、pythonへの引数として-m pdbを指定するとデバッガ付きの実行になります。

python -m pdb ファイル名.py

ドキュメント :
pdb

ソースコードブレークポイントを記述する : import pdb; pdb.set_trace()

ソースコードの任意の場所でブレークポイントでプログラムを止めたい場合、pdb.set_trace()を呼びます。デバッガ付きの実行でなくても、呼ばれたタイミングでデバッガが起動します。

ドキュメント :
pdb.set_trace

デバッガコマンド(pdb)

コマンド(省略形)引数説明
help(h)コマンド名引数なし : 利用できるコマンドの一覧を表示
引数あり : 引数で指定されたコマンドのヘルプを表示
next(n)ステップ実行(ステップオーバー)
step(s)ステップ実行(ステップイン)
return(r)ステップ実行(ステップアウト)
continue(c)再開
!文(Pythonコード)Pythonコード(文)を実行。コード先頭の単語がデバッガコマンドと被らない場合、`!`は省略可能
p式(Pythonコード)Pythonコード(式)を評価し、結果を出力する
quit(q)デバッガ終了。プログラムは中断される

ドキュメント :
デバッガコマンド