はじめに
pythonを勉強していて,小ネタが増えてきたので軽くまとめてみます.
深くまで調べられていない部分もありますが,ご容赦ください.
小ネタ一覧
- 同一性と同値性
- listのコピー
- 関数を引数にとる関数
- 関数を返す関数
- 関数へのプロパティの付与
- アクセス制限
- intの除算
- numpy小ネタ
- 1次元配列の変形
- スライスを使った反転
- vectorize
小ネタ
一覧の上から順に説明していきます.
同一性と同値性
同一性とはオブジェクトが同一であることを,同値性は値が同一であることを指します.
同一性は is
で評価し,同値性は ==
で評価します.
では,それぞれの型について結果を確認します.
int
-5 ~ 256の範囲の整数はメモリ節約のため同一のオブジェクトを使います.
それ以外の整数は,同値であっても同一ではありません.
a = 256
b = 256
a is b # True
c = 257
d = 257
c is d # False
e = -5
f = -5
e is f # True
g = -6
h = -6
g is h # False
float, long, complex
こちらは整数と異なる挙動をします.
同値であっても,格納されているメモリが異なるため同一ではありません.
a = 1.0
b = 1.0
a == b # True
a is b # False
a = 1L
a = 1L
a == b # True
a is b # False
a = 1 + 2j
b = 1 + 2j
a == b # True
a is b # False
bool
True / Falseは一つしか存在しません.
a = True
b = True
a is b # True
a = False
b = False
a is b # True
ちなみに,bool は int のサブクラスであり,False
は 0
,True
は 1
として扱うことができます.
isinstance(False, bool) # True
isinstance(False, int) # True
False == 0 # True
False is 0 # False
True == 1 # True
True is 1 # False
True + True # 2
result = -1
'OK' if result == 0 else 'NG' # 'NG'
('NG', 'OK')[result == 0] # 'NG'
result = 0
('NG', 'OK')[result == 0] # 'OK'
string
特殊文字を含まない文字列は,名前リストにインターンされるため同一です.
スペースや演算子等の特殊文字を含む場合,同値であっても同一ではありません.
ただし,特殊文字一文字だけの場合,同一となります.
a = 'foo'
b = 'foo'
a == b # True
a is b # True
a = 'f o o'
b = 'f o o'
a == b # True
a is b # False
a = 'x+y'
b = 'x+y'
a == b # True
a is b # False
a = '/'
b = '/'
a == b # True
a is b # True
また,以下のような場合には同一になりません.
a = 'f'
a += 'oo'
b = 'foo'
a == b # True
a is b # False
list, tuple, dictionary
list, tuple, dictionaryも文字列同様,同値であっても同一ではありません.
a = [1, 2, 3]
b = [1, 2, 3]
a == b # True
a is b # False
a = (1, 2, 3)
b = (1, 2, 3)
a == b # True
a is b # False
a = {'x': 1, 'y': 2}
b = {'x': 1, 'y': 2}
a == b # True
a is b # False
set
setはユニークな値を持つ集合です.順序の保証がないという特徴があります.
setも同値であっても同一ではありません.
a = set([1, 3, 2])
b = set([1, 3, 2])
c = set([1, 2, 3, 2])
a == b # True
a is b # False
a == c # True -> 順序の情報を保持せず,ユニークな値しか保たないので True
a is c # False
listのコピー
listの注意点として =
を使ってコピーした場合,一方の要素を変更すると,もう一方の要素も変更されます.
a = [1, 2, 3]
b = a
a[0] = [0, 0] # a: [[0, 0], 2, 3], b: [[0, 0], 2, 3] -> a[0]を変更すると,b[0]も変更されます
スライスを使ってコピーした場合,深いコピーとなり,上の問題を防ぐことができます.
a = [1, 2, 3]
b = a[:]
a[0] = 0 # a: [0, 2, 3], b: [1, 2, 3] -> a[0]のみ変更
b[1] = 0 # a: [0, 2, 3], b: [1, 0, 3] -> b[1]のみ変更
ちなみにstring, tupleは要素の変更ができません.
b = 'foo'
b[0] = 'h' # TypeError: 'str' object does not support item assignment
a = (1, 2, 3)
a[0] = 0 # TypeError: 'tuple' object does not support item assignment
関数を引数にとる関数
pythonでは,「関数を引数に取る関数」を定義できます.
def higher(func, x, y):
return func(x, y)
def add(a, b):
return a + b
def sub(a, b):
return a - b
print higher(add, 4, 3) # 7
print higher(sub, 4, 3) # 1
ちなみに lambda
を使うと add
や sub
のような関数を定義する手間を省けます.
def higher(func, x, y):
return fun(x, y)
print higher(lambda a, b: a + b, 4, 3) # 7
print higher(lambda a, b: a - b, 4, 3) # 1
関数を返す関数
関数内で関数を定義し,それを返すように定義します.
外側の関数 f
を実行すると f
内の _f
がリターンされます.
リターンされた _f
は関数であるため,さらに値を渡して実行することができます.
よって,f(1)(2)
のような実行の仕方になります.
def f(x):
def _f(y):
return x + y
return _f
print f(1) # <function _f at 0x10e45b140>
print f(1)(2) # 3
関数へのプロパティの付与
pythonにおける関数は,オブジェクトであるため,自由にプロパティを付与することができます.
どのように使うと便利なのかは分かりませんでした.どなたか教えてください.
def foo():
return '!!!'
foo.x = 1
foo.y = 2
foo.f = lambda x: x + 1
print foo() # !!!
print foo.x # 1
print foo.y # 2.000000
print foo.f(9) # 10
アクセス制限
pythonには,C++やJavaに見られる private
や protected
のようにアクセス制限をかける仕組みがありません.
そこで変数名 or メソッド名の先頭にアンダーバーをつけることで擬似的にアクセス制限をかけています.
アンダーバー1つの場合は,実際に呼び出すことができますが,プライベートメソッドとして実装しているという意図を示しています.
アンダーバー2つの場合は,定義したメソッド名で呼び出すことはできず,アクセス制限がかかった状態になります.
厳密に言うと,呼び出せないのではなく,メソッド名が _(クラス名)__(メソッド名)
に変更されているだけです.
したがって,_(クラス名)__(メソッド名)
の形式で呼び出すことができます.
class Foo(object):
def __init__(self, x):
self.x = x
def f(self, y):
return self.x + y
def _f(self, y):
return self.x + y + 1
def __f(self, y):
return self.x + y + 2
foo = Foo(1)
print foo.f(1) # 2
print foo._f(1) # 3
print foo.__f(1) # AttributeError: 'Foo' object has no attribute '__f'
print foo._Foo__f(1) # 4
intの除算
python 2.xにおける int $\div$ int の計算は,「小数点以下を切り捨てた整数」ではなく「除算の結果を超えない最大の整数」となります.
だからなんだって感じですね.
print 1 / 2 # 0
print -1 / 2 # -1
ちなみに,python 3.xでは,int $\div$ int の計算は小数になります.
また,python 3.xにおいてpython 2.xと同じ挙動にするには,//
を使います.
//
は,python 2.xでも使えます.
1 / 2 # 0.5
1 // 2 # 0
-1 / 2 # -0.5
-1 // 2 # -1
numpy小ネタ
みなさん大好きnumpyです.
1次元配列の変形
要素数 $n$ の1次元配列を shape
で確認すると,(n, )
となります.
これを行ベクトル (1, n)
や列ベクトル (n, 1)
に変形するときは reshape
を使います.
arr = numpy.arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr.shape # (10, )
arr.reshape((1, -1))
# array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
arr.reshape((-1, 1))
# array([[0],
# [1],
# [2],
# [3],
# [4],
# [5],
# [6],
# [7],
# [8],
# [9]])
スライスを使った反転
スライスを使って反転させることができます.
スライスは(開始インデックス):(終了インデックス):(間隔)で操作します.
負の値は後ろからのインデックスを指します.
[-1::-1]
で末尾から先頭にスライスできます.
最初の -1
は省略できます.
X = numpy.arange(9).reshape((3, 3))
# array([[0, 1, 2],
# [3, 4, 5],
# [6, 7, 8]])
X[::-1, :]
# array([[6, 7, 8],
# [3, 4, 5],
# [0, 1, 2]])
X[:, ::-1]
# array([[2, 1, 0],
# [5, 4, 3],
# [8, 7, 6]])
vectorize
numpyのユニバーサル関数の中には,ndarray同士の四則演算や各要素の三角関数,対数をとる関数が定義されています.
自作の関数を各要素に適用する関数を定義するのに vectorize
を使います.
例えば10で割ったときの余りを返す関数をvectorizeに渡して,その関数にndarrayを渡してみます.
X = numpy.arange(25).reshape((5, 5))
# array([[ 0, 1, 2, 3, 4],
# [ 5, 6, 7, 8, 9],
# [10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24]])
numpy.vectorize(lambda x: x % 10)(X)
# array([[0, 1, 2, 3, 4],
# [5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4],
# [5, 6, 7, 8, 9],
# [0, 1, 2, 3, 4]])
おわりに
pythonの小ネタをまとめてみました.
他にもこんなのあるよっていうのあったら教えてください.
何か見つかったら随時追記してきます.
追記情報
@Tsutomu-KKE@github 様,@shiracamus 様,@kochory 様のコメントを参考に修正しました.(2016/06/04)