WEB 初心者向け

【Python】文法を整理した

ちょっと流行りは去ったけど、まだまだPythonは人気ですね。もはやプログラマーの基本スキルと言ってもよさげ。

この記事で解決できること

  • Pythonの基本文法を知ることができる。

関連記事

【Windows版】Pythonをインストールして動かしたい

【Python】文法を整理した

ひとりごと

かつて、最初に習得すべき言語はC言語一択という時代があり、私もC言語を徹底的に覚えたものです。エンジニアたるもの、まず速度や堅牢性を考えるべきだよね。だとしたらC/C++/Javaあたりは最低限押さえておくべきなどと、ついつい考えてしまうワタクシですが、WEBが世の中のインフラとなった現在においてJavaScript、Ruby、PHPあたりを覚えると良く、機械学習をするにはPythonが便利、という意見を多く見かけます。WEBも興味がありますが、機械学習に強く惹かれるのでPythonに着手しました。

AndroidアプリでPythonを実行します

QPython3 - Python3 for Androidを使います。スマホだけでPythonプログラミングとブログ作成が出来るのがメインの理由。※これを書いてた当時、育児が忙しくてスマホで全てのことをやってました。

Python入門を参考にさせて頂きました。バージョンは3を前提にします。

Pythonの基本

①文、式

改行かセミコロンで文が区切られる。セミコロン入れなくてもエラーにならないのはいいですね。

②コメント

#(シャープ)の後はコメント。3連クォート(”””)(’‘’)でコメントをはさむと複数行のコメントを書ける。

③インデント

同じ数の空白でインデントされた文がブロックとみなされる(超重要)。

ブロックと言われると、ついつい波カッコ(curly bracket:{})でくくりたくなる。【空白は何個が正解?】pythonのインデントについて解説を読むと、PEP8でインデントは空白4個が推奨されてるみたいですが、空白2個とか使う人も多いみたい。

④エンコードルール

文字コード、色々選べます。

日本語でコメントとか文字列を書きたいならUTF-8指定すれば良し。

UTF-8をEmacsっぽく書くとこうなるらしい。

衝撃の事実!? "# -*- encoding: utf-8 -*-"じゃなくてもいいんです!を読むと_*_がEmacsのエンコーディング指定プラグマと呼ばれるモノということがわかります。

Pythonのcoding: ナントカのことがよく分からないから調べてみたを読むとPEP-263にエンコーディング指定方法が説明されてます。

⑤数値・文字列・型

Python3では整数(int)、長整数(long)は廃止された。末尾にl(小文字のエル)L(大文字のエル)を付けるとエラーになる。長整数の桁数制限はなく、メモリが許す限りOK。計算誤差もない。

浮動小数点数(float)はこんな感じ。指数表記もできます。

虚数(complex)はこんな感じ。j(小文字のジェイ)J(大文字のジェイ)を指定します。個人的には小文字のジェイがカッコいいと思う。

論理値(bool)はこんな感じ。True、Falseという具合に頭文字は大文字。数値の0、空文字(””)、空リスト([])、空タプル(())、空辞書({})はFalse。

文字列(string)はこんな感じ。”(ダブルクォート)’(シングルクォート)でくくる。

ダブルクォートで囲んだ文字列の中にシングルクォートを入れて良し。シングルクォートで囲んだ文字列の中にダブルクォートを入れて良し。

ダブルクォートで囲んだ文字列の中にダブルクォートを入れたいならエスケープ(バックスラッシュ\
)を前に付ければ良し。

文字列の途中にバックスラッシュ(\)を入れると複数行に分けられる。

文字列の前にr(小文字アール)R(大文字アール)をつけるとエスケープ(バックスラッシュ\)が無視される。

三重クォート(""")(’‘’)で文字列を囲うと途中に改行を入れることが可能。

複数の文字列をスペースで区切ると連結できる。

Python3.3以降は普通に””、’’で囲った文字列はUnicode文字列となる、(u)(U)を付けてもUnicode文字列となる。(b)(B)を付けるとバイト列になる。Python2.xは普通の文字列はバイト列、Python3.0~3.2では(u)(U)がエラーになったみたい。Unicode文字列でエスケープシーケンス(\)を無効化したいときは(ur)(UR)をつける。

エスケープシーケンスはこんな感じ。

書式付き文字列はこんな感じ。

⑥変数・定数

変数はこんな感じ。アンダーバー(_)を含む英数字。1文字目は数字以外。

定数はサポートされてない。C言語の#defineマクロみたいに英大文字とアンダーバー(_)で書くのが慣例のよう。

ドキュメントストリングはこんな感じ。モジュール、クラス、関数の先頭に三重クォート(""")で囲んだコメントは、ドキュメントストリング と呼ばれ、モジュールオブジェクト、クラスオブジェクト、関数オブジェクトの __doc__ アトリビュートで参照できる。

インタラクティブモード中、help()にモジュール名を指定すると__doc__が参照できる。

⑦リスト・タプル・辞書

リスト(list)はこんな感じ。

a = [ 1, 2, 3, 4 ];

b = [
'One',
'Two',
'Three',  最後のカンマは省略可能
];

c = {
1,
'one', 最後のカンマは省略可能
};

d = [ 1, 2, 3, 4 ];
for idx in d:
print( idx );

e = [ 1, 2, 3, 4 ];
print( e[0] ); => 1 インデックス0
print( e[2] ); => 3 インデックス2

f = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
print( f[2:5] ); => 3,4,5 インデックス2からインデックス5の前(インデックス4)まで

g = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
print( f[1:8:2] ); => 2,4,6,8 インデックス1からインデックス7(8-1)まで2個飛ばし

h = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
print( f[-1] ); => 9 マイナスをつけると後ろから数える。後ろから1番目。
print( f[-5:-3] ); => 5,6 後ろから5番目から3番目の前(4番目)まで。

i = [ 1, 2, 3, 4, 5 ] + [ 6, 7, 8, 9]; +でリストを結合できる。
print( i ); => 1, 2, 3, 4, 5, 6, 7, 8, 9

j = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
print( len( j ) ); => 9 len(リスト)でリストの要素数を計算できる。

k = [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]; リストのリストを作ることが出来る。
for idx1 in k:
for idx2 in idx1:
print( idx2 ); => 1,2,3,4,5,6

タプル(tuple)はこんな感じ。

a = ( 1, 2, 3 );

b1 = ( 10 ); 数値の10
b2 = ( 10 ); タプルの10。要素が1つの場合は最後にカンマが要る。

c1 = [ 1, 2, 3, 4 ];
c2 = ( 1, 2, 3, 4 );
c1[ 1 ] = 5; OK:リストは要素の変更ができる。
c2[ 1 ] = 5; NG:タプルは要素の変更ができない。
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
c2[ 1 ] = 5;
TypeError: 'tuple' object does not support item assignment

d1 = [ 1, 2, 3, 4 ];
d2 = ( 1, 2, 3, 4 );
print( tuple( d1 ) ); => (1, 2, 3, 4 ) リストからタプルへの変換
print( list( d2 ) ); => [ 1, 2, 3, 4 ] タプルからリストへの変換

辞書(dict)はこんな感じ。

a = { "pavement1234": 1234, "spaceshiptrain999": 999 , "m78seiun":78 };
print( a ); => {'pavement1234': 1234, 'spaceshiptrain999': 999, 'm78seiun': 78}
print( a[ "pavement1234" ] ); => 1234
print( a[ "spaceshiptrain999" ] ); => 999
print( a[ "m78seiun" ] ); => 78

b = { "pavement1234": 1234, "spaceshiptrain999": 999 , "m78seiun":78 };
for key, value in b.items():
print( key, value ); =>
pavement1234 1234
spaceshiptrain999 999
m78seiun 78

for key in b.keys():
print( key, b[ key ] ); =>
pavement1234 1234
spaceshiptrain999 999
m78seiun 78

for value in b.values():
print( value ); =>
1234
999
78

for key, value in b.iteritems():
print( key, value ); =>
Traceback (most recent call last):
File "<pyshell#61>", line 1, in <module>
for key, value in b.iteritems():
AttributeError: 'dict' object has no attribute 'iteritems'
Python3はiteritems()が無くなった。

リスト関数(map()、filter()、reduce())はこんな感じ。

map()はリストの各要素に指定処理を実行し結果を返す。

def multiple_of_2( x ): return x * 2;
a = [ 1, 2, 3 ];
print( map( multiple_of_2, a ) ); => <map object at 0x03957C70>
Python2はmap()を呼ぶとリストを返したが、Python3はiterator objectを返すようになったらしい。
print( list( map( multiple_of_2, a ) ) ); => [2, 4, 6] list()で変換すれば良い。
print( list( map( lambda x: x * 2, a ) ) ); => [2, 4, 6] print( [ x * 2 for x in a ] ); => [2, 4, 6] 内包表記と言うらしい。また後で出てくる。

ちなみにlabmdaは無名関数。以下のように書きます。

lambda 引数: 戻り値 

filter()はリストの各要素に指定処理を実行しTrueのものだけを返す。

def is_xjapan( x ): return x == 'x-japan';
a = [ 'x-japan', 'y-japan', 'z-japan' ];
print( filter( is_xjapan, a ) ); => <filter object at 0x03957BD0>
Python2はfilter()を呼ぶとリストを返したが、Python3はiterator objectを返すようになったらしい。
print( list( filter( is_xjapan, a ) ) ); => ['x-japan'] ist()で変換すれば良い。
print( list( filter( lambda x: x == 'x-japan', a ) ) ); => ['x-japan'] print( [ x for x in a if x == 'x-japan' ] ); => ['x-japan'] 内包表記。

reduce() はリストの最初の2要素を引数に処理を実施。処理結果と次の要素を引数に処理を実施。を繰り返し、最終的に1つの結果を返します。以下の処理はすべての要素の掛け算が計算されます。

from functools import reduce Python3からredice()はグローバル関数ではなくなったのでfunctoolsからインポートする必要があります。
def mul( x, y ): return x * y;
a = [ 1, 2, 3, 4, 5 ];
print( reduce( mul, a ) ); => 120 (1*2*3*4*5)
print( reduce( lambda x,y: x*y, a ) ); => 120 (1*2*3*4*5)

リストの内包表記はこんな感じ。

[counter for counter in iterator] 基本構文はこんな感じ

pythonの内包表記を少し詳しくを読むと一般的に内包表記にすると速度が2倍になるとか。理由はループの度にリストオブジェクトのappendを参照、appendはPythonの関数として実行される。とのこと。

a = [ 2, 4, 6 ];
print( [ xxx * 3 for xxx in a] ); => [6, 12, 18] print( [ xxx * 3 for xxx in a if xxx == 6] ); => 18
print( [ [ xxx, xxx * 3 ] for xxx in a ] ); => [[2, 6], [4, 12], [6, 18]] print( [ ( xxx, xxx * 3 ) for xxx in a ] ); => [(2, 6), (4, 12), (6, 18)]

b = [ 9, 8, 7 ];
print( [ xxx * yyy for xxx in a for yyy in b ] ); => [18, 16, 14, 36, 32, 28, 54, 48, 42] print( [ a[ idx ] * b[ idx ] for idx in range( len( a ) ) ] ); => [18, 32, 42]

セット(set)はこんな感じ。
重複のないリストを作ります。セット同士のOR、AND、XOR、引き算ができます。足し算はできません。

a = set( [ 'one', 'two', 'three' ] );
b = set( [ 'three', 'four', 'five', 'six' ] );
aとbは'three'が重複しています。
print( a ); => {'one', 'two', 'three'}
print( b ); => {'three', 'five', 'six', 'four'} なんか順番変だけどいいか。
print( a + b ); =>
Traceback (most recent call last):
File "<pyshell#124>", line 1, in <module>
print( a + b );
TypeError: unsupported operand type(s) for +: 'set' and 'set' set同志の足し算はできない
print( a - b ); => {'one', 'two'} aからbの要素three’が除かれた
print( a | b ); => {'six', 'five', 'two', 'one', 'three', 'four'} aとbの要素すべて
print( a & b ); => {'three'} 
three’のみ
print( a ^ b ); => {'five', 'two', 'six', 'one', 'four'} three’以外すべて

print( 'five' in a ); => False aにfive’はないのでFalse

b.add( 'ten' ); bに’ten’を追加
print( b ); => {'ten', 'five', 'three', 'six', 'four'} ’ten’が増えた

⑧演算子

代数演算子(+、-、*、/、%、**、//)はこんな感じ。

+a 正数
-a 負数
a + b 加算
a - b  減算
a * b 乗算
a / b 除算
a % b aをbで割った余り
a ** b aのb乗
a // b 切り捨て除算

ビット演算子(~、&、|、^、<<、>>)はこんな感じ。

~a ビット反転
a & b AND:論理積
a | b OR:論理和
a ^ b XOR:排他的論理和
a << b bビット左シフト
a >> b bビット右シフト

代入演算子(=、+=、-=、*=、/=、%=、**=、//=、&=、|=、^=、<<=、>>=)はこんな感じ。

a = b aにbを代入
a += b a = a + b
a -= b a = a - b
a *= b a = a * b
a /= b a = a / b
a %= b a = a % b
a **= b a = a ** b
a //= b a = a // b
a &= b a = a & b
a |= b a = a | b
a ^= b a = a ^ b
a <<= b a = a << b
a >>= b a = a >> b

比較演算子(==、!=、<、>、<=、>=、<=>、===)はこんな感じ。

a == b aとbは等しい
a != b aとbは異なる
a < b aはbより小さい
a > b aはbより大きい
a <= b aはb以下
a >= b aはb以上
a <> b aとbは異なる
a is b aとbは等しい
a is not b aとbは異なる
a in b aはbに含まれる
a not in b aはbに含まれない

ブール演算子(and、or、not)はこんな感じ。

a and b aとbが真であれば真
a or b aかbが真であれば真
not a aが偽であれば真

条件演算(if - else)はこんな感じ。

x if c else y cが真であればxを返す。cが偽であればyを返す。

文字列演算(+、*、[n:m])はこんな感じ。

a + b 文字列aと文字列bを連結
a * n 文字列aをn回繰り返す。
a[n] 文字列aのn番目の文字を取り出す。
a[n:m] 文字列aのn番目からm番目の文字列を取り出す。
a[n:] 文字列aのn番目から最後までの文字列を取り出す。
a[:m] 文字列aの0番目からm番目の文字列を取り出す。
a[n:m:s] 文字列aのn 番目から m 番目の文字列をs個とばしで取り出す。

⑨制御構文

条件文(if、else、elsif)はこんな感じ。

【文法】
if expr:
...
[elif expr:
...] [else:
...]

point = 78;
if point < 25:
print( "red" );
elif point < 50:
print( "yello" );
else:
print( "green" );
=>
green

whileループ(while、else)はこんな感じ。

【文法】
while expr:
...
[else:
...]

n = 0
while n < 10:
print( n );
n += 1;
else:
print("exit");
=>
0
1
2
3
4
5
6
7
8
9
exit

forループ(for、in)はこんな感じ。

【文法】
for var in expr:
...
[else:
...]

for idx in [ 1, 2, 3 ]:
print( idx ); => 1, 2, 3

for idx in (1, 2, 3):
print( idx ); => 1, 2, 3

for key in { 'one': 1, 'two': 2, 'three': 3 }:
print( key ); => one, two, three

for ch in "123":
print( ch ); => 1, 2, 3

for line in open( "a.txt" ):
print( line ); => ファイル内容が1行ずつ表示される

for idx in range( 10 ):
print( idx ); => 1, 2, 3. 4. 5.6 .7 .8 .9

for ch in u"あいうえお":
print( ch ); =>あ,い,う,えお

for idx in [ 1, 2, 3 ]:
print( idx );
else:
print( 'END' ); => 1, 2, 3, END

ループを抜ける(break)はこんな感じ。

for idx in range( 10 ):
if idx == 5:
break;
print( idx ); => 0, 1, 2, 3, 4 5でループを抜ける。

ループを繰り返す(continue)はこんな感じ。

for idx in range( 10 ):
if idx == 5:
continue
print( idx ); => 0, 1, 2, 3, 4, 6, 7, 8, 9 5はスキップされる。

例外処理(try、except、else、finally、raise)はこんな感じ。

【文法】
try:
...
[except [expr]:
...] [else:
...] [finally:
...]

str = 'ABC';
try:
ch = str[ 5 ]; # 5番目の文字が無い。IndexError例外発生。
except IOError:
print( 'IOError exception' );
except IndexError:
print( 'IndexError exception' );
except:
print( 'Unknown exception' );
else:
print( 'no exception' );
finally:
print( 'Finally' ) # 常にこの行は実行される。
=>
IndexError exception
Finally

raiseは例外を発生させる。

str = 'ABC';
try:
ch = str[ 5 ];
except IndexError:
print( "IndexError except" );
raise
except:
print( "unknown except" );
finally:
print( "finarry" );
=>
IndexError except
finarry
Traceback (most recent call last):
File "C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 3, in <module>
ch = str[ 5 ];
IndexError: string index out of range

try:
raise SystemError( 'SystemError Dummy occured.' )
except SystemError as err:
print("SystemError");
print( err );
=>
SystemError
SystemError Dummy occured.

class UserException( Exception ):
def __init__( self, file, linenum ):
self.file = file
self.linenum = linenum

try:
raise UserException( "a.txt", 12345 )
except UserException as err:
print( "UserException" );
print( err.file );
print( err.linenum );
=>
UserException
a.txt
12345

with文(with)はこんな感じ。

with expr [ as target ] [ , expression [ as target ] ]... :
...

withブロックが終了時にオブジェクト終了処理(例えばファイルクローズ)が自動で呼ばれます。

# withなし
file = open( "a.txt" );
print( file.read() );
file.close(); ファイルクローズが要る

# withあり①
with open( "a.txt" ) as file:
print( file.read() ); ファイルクローズが要らない

# withあり②
file = open( "a.txt" );
with file:
print( file.read() ); ファイルクローズが要らない

アサーション文(assert)はこんな感じ。

assert はデバッグ時に値のチェックをするための仕組み。__debug__ が True の時のみ動作し、デバッグ対象の評価式がFalseであれば、AssertionError例外が発生。python を -O オプション付きで起動することで、__debug__ の値は False になる。

print( __debug__ ); => True

num = 1;
assert num == 2;
=>
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
assert num == 2;
AssertionError

assert exprは以下と等価

if __debug__:
if not expr: raise AssertionError

例えばこんな感じ。

num = 1;
if __debug__:
if not num == 5: raise AssertionError
=>
Traceback (most recent call last):
File "<pyshell#20>", line 2, in <module>
if not num == 5: raise AssertionError
AssertionError

パス文(pass)はこんな感じ。
何もしない文。空の関数、クラスなどを作るときに書く。

def UserFunction():
pass

class UserClass:
pass

デリート文(del)はこんな感じ。
オブジェクトを削除する。

x = 12345;
y = [ 9, 8, 7 ] z = UserClass()
del x, y, z

print文(print)はこんな感じ。

変数やオブジェクトを標準出力に表示する。

print( 3 ); => 3
print( [ 1, 2, 3 ] ); => [1, 2, 3] print( ( 1, 2, 3 ) ); => (1, 2, 3)
print( { 'key1':10, 'key2':20 } ); => {'key1': 10, 'key2': 20}

print( "AAA", "BBB" ); => AAA BBB 引数をカンマで区切るとスペース空けて表示される。

print( "改行なし", end="" );
print( ”改行あり" );
=> 改行なし改行あり end=""を指定すると改行なしになる。

print( "%s" % "書式指定" ); => 書式指定 1つ前の記事で、書式指定は色々やったので今回は割愛。

リダイレクトするのにPython2で使えた>>は使えない。こうなる。

with open( "a.txt", "w" ) as f:
print( "ファイルに出力", file=f );
=> 何も表示されないがa.txtに”ファイルに出力”という文字が書かれる。

print文で複数の値を出力すると半角スペースで区切られる。半角スペースを入れたくない場合、sys.stdout.write() を使用する。

import sys
sys.stdout.write("Hello")
sys.stdout.write("World")
=> HelloWorld

exec文(exec)はこんな感じ。
引数の文字列をPythonのスクリプトとして実行する。

exec statements [ as global [ , local ] ]

exec( "print( 'hello' )" );
=> hello

exec( "print( global_param, local_param )", { "global_param": 100 },{ "local_param": 200 } )
=> 100 200

⑩関数

関数(def)はこんな感じ。
def 文を用いて関数(function)を定義することができます。return文には関数の戻り値を指定します。return 文を省略すると関数は None を返します。

def mul( x, y ):
ret = x * y;
return ret;

ret = mul( 3, 5 );
print( ret ); => 15

def repeater( message, repeat=3 ):
for idx in range( repeat ):
print( message );

repeater('Google') => Google, Google, Google
repeater('Yahoo', repeat=5 ) => Yahoo, Yahoo, Yahoo, Yahoo, Yahoo

*paramsは残りの順序引数を受け取る。
**key_paramsはキーワード付き引数を辞書型で受け取る。

def function( param1, param2, *params, **key_params ):
print( param1 );
print( param2 );
print( params );
print( key_params );

function( '1', '2', '3', '4', key1='Key1', key2='Key2' );
=>
1
2
('3', '4')
{'key1': 'Key1', 'key2': 'Key2'}

params = ( '3', '4' )
key_params = { 'key1': 'Key1', 'key2': 'Key2' }
function( '1', '2', *params, **key_params );
=>
1
2
('3', '4')
{'key1': 'Key1', 'key2': 'Key2'}

関数は複数の値を返すことが出来る。

def function():
return( 999, "ZZZ" );

param1, param2 = function();
print( param1, param2 );
=>999 ZZZ

関数定義の冒頭には"""で ドキュメントストリングを記述できます。

def function( x, y ):
"""Function"""
return( x + y );

グローバル変数(global)はこんな感じ。
関数の外部で定義された変数はグローバル変数として扱われる。関数の中でグローバル変数を参照することはできるが、代入することはできない。代入する場合はglobalで宣言する必要がある。

g_val = 2; #グローバル変数

def function():
global g_val; #global宣言してやれば
print( g_val ); #参照可能
g_val += 1; # 代入もできる。

function();

global宣言せずに関数内でグローバル変数を参照しようとすると、こうなる。

globals()でグローバル変数、locals()でローカル変数の一覧を辞書を返却してくれる。

def function():
for key in globals().keys():
print( "GLOBAL: %s = %s" % ( key, globals()[ key ] ) );
for key in locals().keys():
print( "LOCAL: %s = %s" % ( key, locals()[ key ] ) );

function()
=>
GLOBAL: __name__ = __main__
GLOBAL: __doc__ = None
GLOBAL: __package__ = None
GLOBAL: __loader__ = <class '_frozen_importlib.BuiltinImporter'>
GLOBAL: __spec__ = None
GLOBAL: __annotations__ = {}
GLOBAL: __builtins__ = <module 'builtins' (built-in)>
GLOBAL: __file__ = C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py
GLOBAL: function = <function function at 0x03CBC300>
LOCAL: key = key

ラムダ式(lambda)はこんな感じ。
名前のない小さな関数を作れる。ラムダ式は式なので関数の引数に入れることが出来る。ラムダ式はもちろんラムダ計算から来てるものと思います。ラムダ計算について調べた(前編)とか読むともっとわかります。が、私的にラムダというと、フルメタルパニックに出てくるラムダ・ドライバという虚弦斥力場生成システム(きょげんせきりょくばせいせいシステム)を思い出します。ラムダってなんかカッコいい。さらに余談が続きますが、職場で誰かがrootをrotとtypoしたことをきっかけにrot(回転:ローテート)div(発散:ダイバージェンス)grad(勾配:グラディエント)なんてベクトル計算の話に発展。しかしダイバージェンスと言われても、もはやSTEINS;GATEのダイバージェンスメータぐらいしかパッと出てきません。ナブラ(∇)とかラプラス(?)とかテンソル積とか、もはや記憶の彼方。こんなんで機械学習とかできるのかね。中学生にも分かるTensorFlow入門 その1 テンソルとはなにかあたりから始めようかと思う今日この頃。

LambdaFunction = lambda x, y: x * y
print( LambdaFunction( 4, 8 )
=> 32

イテレータ(iterator)はこんな感じ。

イテレータはfor文で使用することができる繰り返し機能を持つオブジェクト。イテレータオブジェクトは__iter__()でnext()メソッドを持つオブジェクトを返却。next()メソッドは次の要素を返却し最後にStopIteration例外を返すようにする。

class IterClass:
def __init__( this):
this.data = ( 9, 8, 7, 6, 5 )
this.index = 0
def __iter__( this ):
return this
def __next__( this ):
if this.index < len( this.data ):
this.index += 1
return this.data[ this.index - 1 ] else:
raise StopIteration

シンプルで良いですね。
for idx in IterClass():
print( idx );
=> 9 8 7 6 5

上のfor文は、こんな感じの動作をしてるみたい。
it = IterClass().__iter__()
while 1:
idx = it.__next__()
try:
print( idx )
except StopIteration:
break
=> 9 8 7 6 5
Traceback (most recent call last):
File "C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 25, in <module>
idx = it.__next__()
File "C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 14, in __next__
raise StopIteration
StopIteration

ジェネレータ(yield)はこんな感じ。
yieldはイテレータを返却するジェネレータを定義する際に用いられる。

まずYieldを使用しない例。

def NonYieldFunction( list ):
ret = [] for idx in list:
ret.append( idx * 5 )
return ret

for idx in NonYieldFunction( [ 1, 2, 3, 4, 5 ] ):
print( idx )
=>[ 5, 10, 15, 20, 25 ]

次にYieldによるイテレータを使った例。

def YieldFunction( list ):
for idx in list:
yield idx * 5

for idx in YieldFunction( [ 1, 2, 3, 4, 5 ] ):
print( idx )
=>[ 5, 10, 15, 20, 25 ]

どちらも実行結果は変わらないが、パフォーマンスに差がでます。NonYieldFunctionが[ 5, 10, 15, 20, 25 ]のリストを返すのに対してYieldFunctionはイテレータオブジェクトを返します。

NonYieldFunctionの場合、関数呼び出し時に10000要素のリストを渡すと、スタックに10000要素のリストが積まれます。YieldFunction(イテレータ)の場合、リストの要素を1つ取っては計算しを繰り返すので、リストの要素1個分のスタックメモリが消費されるだけです。

例えば、巨大なファイルから特定のキーワードを探し出すようなプログラムの場合、Yieldを使わないとまずファイルを全てスタックに読み込む必要がありますが、Yieldを使えば1行ずつスタックに読み込みキーワードを発見したら抜ければ良いので処理が軽いです。

デコレータ(@)はこんな感じ。
関数を実行する前後に特殊な処理を実行したい場合、@デコレータを使うと
下記の例では、exec()関数を UserDecorator でデコレート(装飾)しています。デコレーション関数では、関数実行前に start を、関数実行後に end を出力しています。

def UserDecorator ( function ): # デコレータ関数を定義する
def wrapper():
print( "start" ) # 前処理を実行する
function() # デコレート対象の関数を実行する
print( "end" ) # 後処理を実行する
return wrapper

@UserDecorator
def exec():
print( "exec" )

exec()
=> start exec end

デコレータの活用事例です。調査対象関数functionに@UserDecoratorをつけることで、関数名、引数、戻り値を表示できます。functoolsのwraps()は調査対象関数の関数名、ドキュメントストリング(__doc__)を後で参照するために呼び出します。

def UserDecorator( function ):
import functools
@functools.wraps( function )
def wrapper( *args, **args2 ):
print( "FunctionName:", function.__name__ )
print( "Arguments:", args )
print( "Keywords:", args2 )
ret = function( *args, **args2 )
print( "Return:", ret )
return ret
return wrapper

@UserDecorator
def function( msg1, msg2, key=1, mode=2 ):
"""function"""
print( "----", msg1, msg2, "----" )
return 9999

n = function( "arg1", "arg2", key=1 )
print( n )

print( repr( function ) )
print( function.__doc__ )
=>
FunctionName: function
Arguments: ('arg1', 'arg2')
Keywords: {'key': 1}
---- arg1 arg2 ----
Return: 9999
9999
<function function at 0x0321D540>
function

⑪クラス

クラス(class)はこんな感じ。慣例でクラス名の先頭は大文字にするみたい。

class UserClass:
"""UserClass"""#ドキュメントストリング(後で__doc__で参照できる)
def __init__( this): # コンストラクタ
this.name = ""

def getName( this): # getName()メソッド
return this.name

def setName( this, name ): # setName()メソッド
this.name = name

cls = UserClass() # クラスのインスタンスを生成
cls.setName("pavement1234") # setName()メソッドをコール
print( cls.getName() ) # getName()メソッドをコール
=>pavement1234

クラス変数・インスタンス変数(attribute)はこんな感じ。
クラスは、インスタンス変数 と クラス変数 を持つことができる。インスタンス変数は【インスタンス.変数名】で表されインスタンス毎に独立の変数である。インスタンス変数はコンストラクタ__init__の中で初期化することが推奨される。

class UserClass:
def __init__( this ):
this.name = "" # インスタンス変数

instance1 = UserClass()
instance1.name = "instance 1"
print( instance1.name )
=> instance 1

instance2 = UserClass()
instance2.name = "instance 2"
print( instance2.name )
=> instance 2

クラス変数は【クラス名.変数名】で表され、すべてのインスタンスで共通の変数。

class UserClass:
PI = 3.14 # クラス変数

print( UserClass.PI ) # 3.14
=> 3.14

クラス変数でインスタンス数をカウントアップする。

class UserClass:
count = 0 #クラス変数を0に初期化

def __init__( this ):
UserClass.count += 1 # クラス変数をカウントアップ

instance1 = UserClass()
instance2 = UserClass()
print( UserClass.count )
=> 2

クラス変数、インスタンス変数は実行中に追加できる。

class EmptyClass:
pass #空のクラス

instance = EmptyClass()
instance.name = "instance" # インスタンス変数の追加
EmptyClass.PI = 3.14 # クラス変数の追加

print( instance.name );
print( EmptyClass.PI )
=> instance 3.14

インスタンス変数が存在しない場合【インスタンス.変数名】はクラス変数を参照することに注意。
【インスタンス.変数名】に値を代入するとインスタンス変数が生成される。
以降【インスタンス.変数名】でインスタンス変数が参照される。

class UserClass:
PI = 3.14

instance1 = UserClass()
instance2 = UserClass()
print( instance1.PI ) # 【インスタンス.変数名】を指定したが
# インスタンス変数が存在しないのでクラス変数が参照される。
=>3.14
instance1.PI = 3.14159 # インスタンス変数instance1.PIが生成される。
print( instance1.PI ) # インスタンス変数 instance1.PI(3.14159)が参照される
=>3.14159
print( instance2.PI ) # クラス変数 UserClass.PI(3.14) が参照される
=>3.14

Pythonのclassにはprivate、protectedはなく全てpublic。

メソッド(method)はこんな感じ。

クラスが持つ関数はメソッドと呼ばれる。メソッドもpublic。メソッドの第一引数は必ずクラスのインスタンスを指定する。第二引数以降にメソッドの引数を受け取ることが出来る。

class UserClass:
name = ""
def setName( this, name ): #第一引数は自分のインスタンス(this)
this.name = name
def getName( this ):
return this.name

instance = UserClass()
instance.setName( "pavement1234" )
print( instance.getName() )
=> pavement1234

アクセス制限(_、__)はこんな感じ。

Pythonはprivate、protectedはサポートされていない。
アンダーバー(_)で始まる変数や関数は外から参照しないという慣習的ルールがある。
アンダーバー2個(__)で始まる変数や関数は参照が制限され、AttributeError例外が発生する。
しかしアンダーバー2個(__)で始まる変数/関数も、_クラス名__変数名/関数名にすればアクセス出来てしまう。

class UserClass:
def __init__( this ):
this.name = "pseudonym"
this._name = "real name"
this.__name = "indian name"

def function( this ): print( 'public' )
def _function( this ): print( 'private' )
def __function( this ): print( 'secret' )

instance = UserClass()

print( instance.name ) # 参照OK
=>pseudonym
print( instance._name ) # 参照OKだがしない
=>real name
print( instance.__name ) # 参照できない(AttributeError例外)
=>
Traceback (most recent call last):
File "C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 15, in <module>
print( instance.__name ) # 参照できない(AttributeError例外)
AttributeError: 'UserClass' object has no attribute '__name'
print( instance._UserClass__name ) # こうやると参照できる
=>indian name

instance.function() # 参照OK
=>public
instance._function() # 参照OKだがしない
=>private
instance.__function() # 参照できない(AttributeError例外)
=>
Traceback (most recent call last):
File "C:\Users\(ログインユーザ名)\AppData\Local\Programs\Python\Python37-32\test.py", line 20, in <module>
instance.__function() # 参照できない(AttributeError例外)
AttributeError: 'UserClass' object has no attribute '__function'
instance._UserClass__function() # こうやると参照できる
=>secret

コンストラクタ(__init__)はこんな感じ。

__init__() メソッドはコンストラクタと呼ばれ、クラスのインスタンスが生成された際に呼び出される。

class UserClass:
def __init__( this, name ):
this.name = name
def getName( this ):
return this.name

instance = UserClass( "pavement1234" )
print( instance.getName() )
=> pavement1234

デストラクタ(__del__)はこんな感じ。

__del__() メソッドはデストラクタと呼ばれ、クラスのインスタンスが消滅するときに呼び出される。

class UserClass:
def __init__( this ):
print( "initialize" )
def __del__( this ):
print( "delete" )

instance = UserClass()
=> initialize
del instance
=> delete

文字列化(__str__)はこんな感じ。
__str__() は、インスタンスを暗黙的に文字列に変換する際の変換処理を定義します。要はprint文にインスタンスを入れると__str__で定義した文字列が返ってくるということですね。

class UserClass:
def __init__( this, name ):
this.name = name

def __str__( this ):
return "I am " + this.name

instance = UserClass( "pavement1234" )
print( instance )
=> I am pavement1234

継承(inheritance)はこんな感じ。

他のオブジェクト指向言語と同様、クラスを継承できる。
下記の例では、ParentClassクラスを継承した、ChildClassというサブクラスを定義した。
サブクラスでは親クラスが持つアトリビュートやメソッドを継承して利用することができる。

class ParentClass:
def parent( this ):
print( "Parent" )

class ChildClass( ParentClass ):
def child( this ):
print( "Child" )

instance = ChildClass()
instance.parent()
=>Parent
instance.child()
=>Child

サブクラスでは、親クラスのメソッドを上書き(オーバーライド)することができる。

class ParentClass:
def exec( this ):
print( "Parent" )

class ChildClass( ParentClass ):
def exec( this ):
print( "Child" )

instance = ChildClass()
instance.exec()
=>Child

親クラス(super())はこんな感じ。
super() は 親クラス を参照する。
第一引数にはクラス、第二引数にはインスタンスを指定する。
下記の例では、サブクラスのコンストラクタの中で、親クラスのコンストラクタを呼び出している。

class ParentClass( object ):
def __init__( this ):
this.valParent = 10000

class ChildClass(ParentClass):
def __init__( this ):
super( ChildClass, this ).__init__()
this.valChild = 99999

instance = ChildClass()
print( instance.valParent )
=>10000
print( instance.valChild )
=>99999

多重継承はこんな感じ。
Pythonは多重継承をサポートする。
下記ではBlack、White両方を継承するYelloを定義しています。

class Black:
def functionBlack( self ):
print( "Black" )

class White:
def functionWhite( self ):
print( "White" )

class Yello( Black, White ):
pass

instance = Yello()
instance.functionBlack()
=>Black
instance.functionWhite()
=>White

クラス階層はこんな感じ。(Python2かもしれない)

object
+- int
| +- bool
+- long
+- float
+- complex
+- basestring
| +- str
| +- unicode
+- list
+- tuple
+- dict
+- file
+- BaseException
+- SystemExit
+- KeyboardInterrupt
+- GeneratorExit
+- Exception
+- StopIteration
+- StandardError
| +- BufferError
| +- ArithmeticError
| | +- FloatingPointError
| | +- OverflowError
| | +- ZeroDivisionError
| +- AssertionError
| +- AttributeError
| +- EnvironmentError
| | +- IOError
| | +- OSError
| | +- WindowsError (Windows)
| | +- VMSError (VMS)
| +- EOFError
| +- ImportError
| +- LookupError
| | +- IndexError
| | +- KeyError
| +- MemoryError
| +- NameError
| | +- UnboundLocalError
| +- ReferenceError
| +- RuntimeError
| | +- NotImplementedError
| +- SyntaxError
| | +- IndentationError
| | +- TabError
| +- SystemError
| +- TypeError
| +- ValueError
| +- UnicodeError
| +- UnicodeDecodeError
| +- UnicodeEncodeError
| +- UnicodeTranslateError
+- Warning
+- DeprecationWarning
+- PendingDeprecationWarning
+- RuntimeWarning
+- SyntaxWarning
+- UserWarning
+- FutureWarning
+- ImportWarning
+- UnicodeWarning
+- BytesWarning

⑫パッケージとモジュール

モジュールはこんな感じ。
1つのスクリプトファイル(*.py)はモジュールとして扱うことができる。
スクリプトファイルから拡張子を除いた名前がモジュール名。
import文にモジュール名を指定すると、モジュールを読み込める。
読み込んだモジュールのクラス、関数、変数は、【モジュール名.識別子】で参照することができる。

module.py

 command
def function():
print( "mod" )

test.py

 command
import module
module.function()
=> mod

モジュールの冒頭に"""ドキュメントストリングを記述できる。

# coding: utf-8
"""module"""
(以下略)

パッケージはこんな感じ。
複数のモジュールをまとめてパッケージとして扱うことができる。
パッケージは、__init__.py という名前のファイルを持つフォルダ、
モジュールは .py ファイルである。
__init__.py にはパッケージの初期化処理を記述する。なければ空でよい。

下記の例ではpack1パッケージの中にpack2パッケージがあり、
pack2パッケージの中にmod.pyモジュールが配置されている。

【フォルダ構成】
フォルダpack1
+ファイル__init__.py
+フォルダpack2
+ファイル__init__.py
+ファイルmod.py

インポート文(import)はこんな感じ。
パッケージの中からモジュールや識別子(クラス、関数、変数…)をインポートするには下記の様にする。

# import [パッケージ.]モジュール
import pack1.pack2.mod
pack1.pack2.mod.function()

# from パッケージ import モジュール
from pack1.pack2 import mod
mod.function()

# from パッケージ import *
from pack1.pack2 import * # __all__の設定が必要
mod.function()

# from [パッケージ.]モジュール import 識別子
from pack1.pack2.mod import function
function()

# from [パッケージ.]モジュール import *
from pack1.pack2.mod import *
function()

上記の例で「from パッケージ import *」の形式を用いるには、
pack2 パッケージの __init__.py ファイルに読み込み対象のモジュールリストを__all__ に定義しておく必要がある。

__init__.py

 command
__all__ = ["mod"]

読み込むモジュールや識別子を複数記述することもできる。

import pack1.pack2.mod1, pack1.pack2.mod2
from pack1.pack2 import mod, mod2
from pack1.pack2 import ( mod, mod2 )
from pack1.pack2.mod import function1, function2
from pack1.pack2.mod import ( function1, function2 )

読み込んだモジュール名や識別子に別名をつけることができる。

import pack1.pack2.mod as mod1
mod1.function()

from pack1.pack2 import mod as mod2
mod2.function()

from pack1.pack2.mod import function as function1
function1()

from には(.)や(..)や(...)を用いてパッケージを相対的に指示することができる。

from . import mod # このパッケージから modモジュールをインポートする
from .. import mod # ひとつ上の階層のパッケージから modモジュールをインポートする
from ... import mod # ふたつ上の階層のパッケージから modモジュールをインポートする
from ...pack4 import mod # ふたつ上の階層のpack4パッケージから modモジュールをインポートする

パッケージ名(__package__)はこんな感じ。
__package__ は現在のパッケージ名を示す。

print( __package__ )
=> None

ファイル名(__file__)はこんな感じ。
__file__ は現在のファイル名を示す。

print( __file__ )
=>C:/Users/(ログインユーザ名)/AppData/Local/Programs/Python/Python37-32/test.py

モジュール名(__name__)はこんな感じ。
__name__は現在のモジュール名を示す。スクリプトとして起動したメインモジュールの場合は __main__という名前が設定されている。下記の例はファイルがpythonコマンドから直接起動された場合のみ実行する処理を記載。

if __name__ == "__main__":
function()

ビルトインモジュール(builtins)はこんな感じ。
builtinsはopen()などのビルトインオブジェクトを包含する仮想的なモジュールを示す。

test.py

 command
import builtins
for line in builtins.open( "test.py" ):
print( line )
=>
import builtins
for line in builtins.open( "test.py" ):
print( line )

まとめ

久々にプログラミング言語に長時間触れました。Pythonはシンプルでなかなか良いですね。最初はAndroidでチマチマやってましたが、だんだんスマホから打つのが面倒になりWindows版PythonのIDLEをフル活用しました。やはりたくさんコードを打つと、それだけ言語に愛着も沸くし、身にもつくってもんです。来週仕事でPythonコードを読むことになりそうなので、良いリハビリになりました。

 

関連記事

【Windows版】Pythonをインストールして動かしたい

【Python】文法を整理した

  • この記事を書いた人
  • 最新記事

ペイヴメント

ペイヴメントのエンジニア塾(当ブログ)では20年以上の経験から得られたプログラミング系ノウハウについてベテランにも満足して頂けるような内容の濃いコンテンツを初心者にも分かりやすい形で日々発信しています。【経歴】ベンチャーのソフトハウスで4年勤務後、精密機器メーカーのソフト開発部門に勤務し今に至ります。

-WEB, 初心者向け

Copyright© ペイヴメントのエンジニア塾 , 2020 All Rights Reserved.