Pythonステップ1-メタグループとリスト
4044 ワード
このシリーズの文章は一連の学習ノートで、Python 3の原理、性能をより深く分析することを望んで、文章の中の大部分の観点はすべて原作の作者の観点(以下)で、本人は本の中の例に対して実践と総括を加えて、そして相応のPythonのC言語のソースコード(3.6.1)を結びつけて、分かち合います.原著:『High Performance Python』by O'Relly Media、著者Micha Gorelick、Ian Ozsvald 『Fluent Python』by O'Relly Media、著者Luciano Ramalho 様々なシーケンス(メタグループ、リストなど)を深く理解することで、車輪を繰り返さないようにすることができます.
シーケンスの分類
一般的な分類は一般にMutableとImmutableによって分類され、Container sequence(要素がオブジェクトのシーケンス):List,Tuple,collections.deque Flat sequence(コンパクトシーケンス):str,bytes,bytearray,memoryview,array.array
リストリスト
List:ダイナミック配列、要素が可変で、サイズ(append,resize)リストを変えることができます.
リスト導出(List Comprehensions)とジェネレータ(Generator)
リスト導出およびジェネレータは、リストおよび他のシーケンスを作成する迅速な方法であり、概要を記述し、高性能なコードを書くことができます.
mapやfilterでもリストをすばやく作成できますが、パフォーマンスにはメリットはありません.
メタグループ、arraysなどのシーケンスを作成する場合は、リストの導出で行うこともできますが、ジェネレータを使用するとメモリをより節約できます.(iterator protocalで要素を生成し、すべて生成してメモリに入れるのではなく)
タプルTuple
**タプルは「変更不可リスト」(Immutable List)**タプルだけでなく「属性なしレコード」(Records with no field name)**としても使用できます.
Tuple as Records
メタグループを可変リストと見なすだけでは、要素の順序は重要ではありません.メタグループを一連の属性と見なすことができ,属性の数は固定的であり,位置も重要である.
位置によって対応する属性を取得することができ、本にはName Tuple,collectionsも紹介されている.nametupleは、属性名を付与したり、名前や場所で属性にアクセスしたりすることができ、Objectよりも軽量です.
Tuple as Immutable List
Tupleはadd,delete,reverseを除いてすべてのListの方法をサポートする.各Pythonプログラマーは、シーケンスがスライスできることを知っています.このようにa[start:stop]、それほど有名ではない知識点があります.
なぜsliceとrangeには最後の要素が含まれていないのかは、sliceの長さ=stop-start をより容易に得ることができる.シーケンスを2つの部分に分割するのが容易であり、a[:3]およびa[3:]
シーケンスの割り当て+=、*=
+=依存iaddの実装,すなわちinplace addition*=依存imulの実装は可変シーケンス(List)に対してinplaceの動作が良好に実現され,可変シーケンス(Tuple)に対しては実現されなかった.
すなわち、1つの可変シーケンスに対して、重複する貼り付け操作は非常に非効率であり、多くのメモリ割り当てとコピー操作を伴う.もう一つのcorner caseは、出力がなぜなのか考えてみましょう.異常を投げ出すとtupleも変化し,結論としてtupleに可変のオブジェクトを持たせないで,重畳付与操作は原子操作ではない.
list.sort vs sort
2つのソート関数があります.リストに付属する関数、list.sortは、リストをその場でソートします.つまり、新しいコピーは生成されません.内蔵のsort関数、sort、新しいリストを作成し、ソートし、新しいリストを返します.
もう一つ重要な常識があります.functions or methods that change an object in place should return None to make it clear to the caller that the object itself was changed,and no new object was created.
シーケンスの分類
一般的な分類は一般にMutableとImmutableによって分類され、Container sequence(要素がオブジェクトのシーケンス):List,Tuple,collections.deque Flat sequence(コンパクトシーケンス):str,bytes,bytearray,memoryview,array.array
リストリスト
List:ダイナミック配列、要素が可変で、サイズ(append,resize)リストを変えることができます.
リスト導出(List Comprehensions)とジェネレータ(Generator)
リスト導出およびジェネレータは、リストおよび他のシーケンスを作成する迅速な方法であり、概要を記述し、高性能なコードを書くことができます.
>>> dummy = [x for x in 'ABC']
>>> dummy
['A', 'B', 'C']
mapやfilterでもリストをすばやく作成できますが、パフォーマンスにはメリットはありません.
(env) MengdeiMac:02-array-seq an$ cat listcomp_speed.py
import timeit
TIMES = 10000
SETUP = """
symbols = '$¢£¥€¤'
def non_ascii(c):
return c > 127
"""
def clock(label, cmd):
res = timeit.repeat(cmd, setup=SETUP, number=TIMES)
print(label, *('{:.3f}'.format(x) for x in res))
clock('listcomp :', '[ord(s) for s in symbols if ord(s) > 127]')
clock('listcomp + func :', '[ord(s) for s in symbols if non_ascii(ord(s))]')
clock('filter + lambda :', 'list(filter(lambda c: c > 127, map(ord, symbols)))')
clock('filter + func :', 'list(filter(non_ascii, map(ord, symbols)))')
(env) MengdeiMac:02-array-seq an$ python listcomp_speed.py
listcomp : 0.012 0.013 0.013
listcomp + func : 0.017 0.018 0.032
filter + lambda : 0.020 0.016 0.025
filter + func : 0.015 0.020 0.025
メタグループ、arraysなどのシーケンスを作成する場合は、リストの導出で行うこともできますが、ジェネレータを使用するとメモリをより節約できます.(iterator protocalで要素を生成し、すべて生成してメモリに入れるのではなく)
タプルTuple
**タプルは「変更不可リスト」(Immutable List)**タプルだけでなく「属性なしレコード」(Records with no field name)**としても使用できます.
Tuple as Records
メタグループを可変リストと見なすだけでは、要素の順序は重要ではありません.メタグループを一連の属性と見なすことができ,属性の数は固定的であり,位置も重要である.
(name, age) = ('Jack', 18)
位置によって対応する属性を取得することができ、本にはName Tuple,collectionsも紹介されている.nametupleは、属性名を付与したり、名前や場所で属性にアクセスしたりすることができ、Objectよりも軽量です.
Tuple as Immutable List
Tupleはadd,delete,reverseを除いてすべてのListの方法をサポートする.各Pythonプログラマーは、シーケンスがスライスできることを知っています.このようにa[start:stop]、それほど有名ではない知識点があります.
なぜsliceとrangeには最後の要素が含まれていないのか
>>> a = [1,2,3,4,5]
>>> a[:3]
[1, 2, 3]
>>> a[3:]
[4, 5]
シーケンスの割り当て+=、*=
+=依存iaddの実装,すなわちinplace addition*=依存imulの実装は可変シーケンス(List)に対してinplaceの動作が良好に実現され,可変シーケンス(Tuple)に対しては実現されなかった.
>>> l=[1,2,3]
>>> id(l)
4322512072
>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
4322512072
>>>
>>>
>>> t=(1,2,3)
>>> id(t)
4322621768
>>> t *= 2
>>> t
(1, 2, 3, 1, 2, 3)
>>> id(t)
4322550888
>>>
すなわち、1つの可変シーケンスに対して、重複する貼り付け操作は非常に非効率であり、多くのメモリ割り当てとコピー操作を伴う.もう一つのcorner caseは、出力がなぜなのか考えてみましょう.異常を投げ出すとtupleも変化し,結論としてtupleに可変のオブジェクトを持たせないで,重畳付与操作は原子操作ではない.
>>> l=(1,2,[30,50])
>>> l[2] += [50,60]
Traceback (most recent call last):
File "", line 1, in
TypeError: 'tuple' object does not support item assignment
>>> l
(1, 2, [30, 50, 50, 60])
>>>
list.sort vs sort
2つのソート関数があります.リストに付属する関数、list.sortは、リストをその場でソートします.つまり、新しいコピーは生成されません.内蔵のsort関数、sort、新しいリストを作成し、ソートし、新しいリストを返します.
もう一つ重要な常識があります.functions or methods that change an object in place should return None to make it clear to the caller that the object itself was changed,and no new object was created.