Python TIPS

Pythonの文法知識を深めていきたい所存.

基本的に,他のプログラム言語を触ったことがあり,かつ大体Pythonは触っているという人向け.

シーケンス

シーケンスはオブジェクトを順番に処理するデータ構造.

文字列/バイト列

Python 3以降ではスクリプトファイルはUTF-8で保存されていることが想定されている.文字の保持としてstr型とbytes型が存在する.

bytes型

これは符号化された文字列データである.バイナリ列.以下のようにbの文字をつけることで生成できる.bytes型はASCII文字種で書かなければならない.(0~255).しかしASCIIで書けない場合は先頭に\xをつけて16進数文字となる.


In [5]:
x = b"This is a pen." # bytes型を生成
type(x)               # bytes型であることがわかる


Out[5]:
bytes

In [11]:
# テストをCP932で符号化したbytes型
x = b'\x83e\x83X\x83g'

比較演算子の面白い動き

Pythonには比較演算子としてand, or, notなどが用意されているがand, orに関しては以下のような面白い動きがある.


In [ ]:


In [2]:
1 and 2


Out[2]:
2

In [3]:
0 and 1


Out[3]:
0

In [4]:
1 or 2


Out[4]:
1

In [5]:
0 or 1


Out[5]:
1

andは左辺が真だった場合に右辺を返し,偽であった場合は左辺を返す.orは左辺が真だった場合に左辺を返し,偽であった場合は右辺を返していることがわかる.これを用いるとPythonでも他の言語にある三項演算子のようなことが行える.


In [12]:
y = 20
x = (y > 10) and "YES" or "NO"
print(x)


YES

つまりは x = 条件 and 真の場合の値 or 偽の場合の値 というようなコードが書ける.更にPython 2.5からは三項演算子的な書き方が追加されたので同じことを以下のようにかける.


In [13]:
y = 20
x = "YES" if y > 10 else "NO"
print(x)


YES

関数デコレータ

関数アノテーション

Pythonは動的型付け言語のため,型を宣言をする必要はない.しかし,あえて型を指定する方法が関数アノテーションである.


In [14]:
def repeat(x: str, y: int) -> str:
    return x * y

print(repeat("ABCDEFG", 3))


ABCDEFGABCDEFGABCDEFG

更にドキュメンテーション文字列としてではなく関数の定義部分に引数の説明や戻り値の注釈を書くことができる.


In [15]:
def add(left: '左項', right: '右項') -> '和':
    return left + right

itertools

この項目は10.1. itertools — 効率的なループ実行のためのイテレータ生成関数¶(原文)の内容をほぼパクったようなものです.

無限イテレータ

無限イテレータはその名の通り何か止まる条件を書かないと止まらないw


In [23]:
# itertools.count(start, [step])
# startから無限大まで
from itertools import *

print("itertools.count(start,[step])")
for i in count(5):
    if i == 10:
        break
    print(i, end=' ')
print()
# itertools.cycle()
# 無限回の繰り返し.最後まで行ってもStopIterationは起きない.
print("itertools.cycle()")
itrs = cycle("ABC")
for i, j in enumerate(itrs):
    if i == 5:
        break
    print(j, end=' ')
print()

# itertools.repeat(obj, times=None)
# objを繰返し生成する.なおtimesがしていされていないと,無限回返す.
# 以下の様なコードを生成するために用いられることが多い
print("itertools.repeat(obj, times=None)")
print(list(map(pow, range(10), repeat(2))))


itertools.count(start,[step])
5 6 7 8 9 
itertools.cycle()
A B C A B 
itertools.repeat(obj, times=None)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

以下の関数はすべてイテレータを作成して返す.


In [34]:
# itertools.accumulate(iters[, func])
# 累積和を返すイテレータを作成する.オプションのfuncは2つの引数を取る必要がある
print("itertools.accumulate(iters[, func])")

for i in accumulate(range(5)):
    print(i,end=" ")
print()

# なお最終的な累積値だけを返す関数はfunctools.reduce()がある.

# itertools.chain(*iters)
# 先頭のitersの全要素を返し, 2番目のiterableの全要素と...と全iterableの要素を返すイテレータを作成する
print("itertools.chain(*iters)")
print(list(chain("ABC", "DEFG")))

# itertools.combinations(iters, r)
# 組み合わせ.長さrの部分列を返す.
print("itertools.combinations(iters, r)")
print(list(combinations("ABCD",2)))  # 出力は辞書順

# 更に返される要素は 0 <= n <= r のときは n! / r! / (n-r)! であり,r > n の場合は0である.

# itertools.product(*iterables, repeat=1)
# 直積を返す.なおジェネレータ式の入れ子forループと等価.
# つまり product(A, B) は ((x, y) for x in A for y in B) と同じ.
# オプションのrepeatはiterable自身との直積を計算するために使用.product(A, repeat=3)はproduct(A, A, A)と等価
print("itertools.product(*iterables, repeat=1)")
print(list(product("ABCD", "xy")))
print(list(product(range(2), repeat=3)))


itertools.accumulate(iters[, func])
0 1 3 6 10 
itertools.chain(*iters)
['A', 'B', 'C', 'D', 'E', 'F', 'G']
itertools.combinations(iters, r)
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
itertools.product(*iterables, repeat=1)
[('A', 'x'), ('A', 'y'), ('B', 'x'), ('B', 'y'), ('C', 'x'), ('C', 'y'), ('D', 'x'), ('D', 'y')]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]

イテレータを使うことでメモリ上にすべての要素を置く必要がなくなり,メモリ効率が良くなる.更に実行の枷であるforループやジェネレータを使う必要がなくなるため,高速化を図ることができる.

さらなる参考文献:

functools

10.2 functools - 高階関数と呼び出し可能オブジェクトの操作


In [3]:
from functools import *
# functools.reduce(function, iterable, initializer=None)
# functionをiterableの要素に対して左から右に累積的に適用する.
print(reduce(lambda x, y: x+y, [1,2,3,4,5])) # ((((1+2)+3)+4)+5)


15

In [ ]: