Pythonチュートリアルで学んだ中で個人的に大事だと思う部分をピックアップしてみた
はじめに
Pythonを業務で触る上で体系的に学び直したいと思い、公式チュートリアルを学ぼうと思いました。
その中でも、自分の中で大事と思ったところをピックアップして記事にしてみました。※学んだことがあったら随時更新(したい。。。)
4. その他の制御フローツール
4.9.6. ラムダ式
ラムダ式を使うと小さなラムダ関数を作成可能。
設定した値を足し引き
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>>
>>> print(f(-1))
41
make_incrementor
関数は、引数n
を取り、lambda x: x + n
というラムダ関数を返します。
このラムダ関数は、引数x
を取り、x
+ n
の結果を返します。
make_incrementor(n)
を呼び出すと、x
にn
を加える関数が生成され、それを返します。
リスト各要素を2倍に
>>> numbers = [1, 2, 3, 4, 5]
>>> doubled = list(map(lambda x: x * 2, numbers))
>>> print(doubled)
[2, 4, 6, 8, 10]
※map
とリスト内包表記
map
構文
map(function, iterable[, iterable2, ...])
function
...関数やラムダ式など
iterable
...リストやタプルなど
map
を使った場合
numbers = [1, 2, 3, 4]
result = map(lambda x: x * 2, numbers)
print(list(result)) # [2, 4, 6, 8]
リスト内包表記を使った場合
numbers = [1, 2, 3, 4]
result = [x * 2 for x in numbers]
print(result) # [2, 4, 6, 8]
5. データ構造
append
とextend
の違い
a = [1, 2, 3]
a.append([4, 5, 6]) # appendを使用
print(a) # 出力: [1, 2, 3, [4, 5, 6]]
a = [1, 2, 3]
a.extend([4, 5, 6]) # extendを使用
print(a) # 出力: [1, 2, 3, 4, 5, 6]
5.1.3 リスト内包表記
平方のリストを作成する
通常の書き方
>>> squares = []
>>> for x in range(10):
... squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
リスト内包表記の書き方
squares = [x**2 for x in range(10)]
リスト内包表記は括弧の中の式、for、そして0個以上のforかifで構成される
下記の式はどちらも等価である
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
combs = []
for x in [1,2,3]:
for y in [3,1,4]:
if x != y:
combs.append((x, y))
combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
5.1.4. ネストしたリストの内包表記
長さ4のリスト3つからなる、3x4 の matrix について考える
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
下のリスト内包表記は、matrix の行と列を入れ替える
[[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
下記コードと等価になる
transposed = []
for i in range(4):
# the following 3 lines implement the nested listcomp
transposed_row = []
for row in matrix:
transposed_row.append(row[i])
transposed.append(transposed_row)
transposed
zip
関数
備考...各リストの対応するインデックスの要素を合わせてタプル化
>>> for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):
... print(item)
...
(1, 'sugar')
(2, 'spice')
(3, 'everything nice')
>>> list(zip(range(3), ['fee', 'fi', 'fo', 'fum']))
[(0, 'fee'), (1, 'fi'), (2, 'fo')]
del
5.2
リストのインデックスを指定して値を削除する
返り値はない
>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>>
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>>
>>> del a[:]
>>> a
[]
5.5. 辞書型 (dictionary)
dict()
コンストラクタ
dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}
リスト内包表記を使って辞書を作成可能
{x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
キーワード引数
dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}
items
)
5.6. ループのテクニック(
辞書に対しitems()
メソッドを使うとキーとそれに対応するため値を取り出せる
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
print(k, v)
gallahad the pure
robin the brave
配列に対しenumerate()
を使うと要素とインデックスを取り出せる
for i, v in enumerate(['tic', 'tac', 'toe']):
print(i, v)
0 tic
1 tac
2 toe
シーケンスを逆方向に渡ってループするには、まずシーケンスの範囲を順方向に指定し、reversed()
を使う。
for i in reversed(range(1, 10, 2)):
print(i)
9
7
5
3
1
6. モジュール
以下解説用のモジュールファイル
fibo.py
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
6.1. モジュールについてもうすこし
as
またはfrom
を使うことでモジュールを任意の名前で扱えるようになる
as
import fibo as fib
fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
from
from fibo import fib as fibonacci
fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
6.11 モジュールをスクリプトとして実行する
モジュールを以下のように実行するとモジュール内のコードが実行できる
$ python fibo.py <arguments>
モジュールの末尾に以下を追加することで、同時にスクリプトとして実行できるようになる
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
モジュールが import された場合は、そのコードは実行されない
import fibo
7. 入力と出力
7.1.2. 文字列の format() メソッド
str.format()
{}
を引数の値に置き換えられる
print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"
print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam
*
,**
可変長引数の使い方(*args
,**kwsrgs
)
備考...
*
(*args
)
引数を可変長にできる。
def my_sum2(*args):
print('args: ', args)
print('type: ', type(args))
print('sum : ', sum(args))
my_sum2(1, 2, 3, 4)
# args: (1, 2, 3, 4)
# type: <class 'tuple'>
# sum : 10
引数は全てタプルに格納される。よってargs
にインデックスでアクセス可能
def show_args(*args):
print(args[0]) # 最初の引数を表示
show_args(10, 20, 30) # 10
**
(**kwargs
)
複数のキーワード引数を辞書として受け取る
def func_kwargs(**kwargs):
print('kwargs: ', kwargs)
print('type: ', type(kwargs))
func_kwargs(key1=1, key2=2, key3=3)
# kwargs: {'key1': 1, 'key2': 2, 'key3': 3}
# type: <class 'dict'>
引数はキーとセットで辞書へ格納される。その辞書へアクセスして値を取得できる。
def show_kwargs(**kwargs):
print(kwargs.get('key1')) # 'key1'の値を表示
show_kwargs(key1=10, key2=20) # 10
with
)
ファイルを読み書きする(
以下公式ドキュメントより
open() は file object を返します。大抵、 open(filename, mode, encoding=None) のように2つの位置引数と1つのキーワード引数を伴って呼び出されます。
f = open('workfile', 'w', encoding="utf-8")
ファイルオブジェクトを扱うときに with キーワードを使うのは良い習慣です。 その利点は、処理中に例外が発生しても必ず最後にファイルをちゃんと閉じることです。 with を使うと、同じことを try-finally ブロックを使って書くよりずっと簡潔に書けます:
with
を使うと自動でclose
が行われる
with open('workfile', encoding="utf-8") as f:
read_data = f.read()
# We can check that the file has been automatically closed.
f.closed
True
7.2.2. json による構造化されたデータの保存
文字列表現からデータを再構築することは、デシリアライズ (deserializing) と呼ばれます。シリアライズされてからデシリアライズされるまでの間に、オブジェクトの文字列表現はファイルやデータの形で保存したり、ネットワークを通じて離れたマシンに送ったりすることができます。
json.dumps()
import json
x = [1, 'simple', 'list']
json.dumps(x)
'[1, "simple", "list"]'
8. エラーと例外
8.3. 例外を処理する
while True:
try:
x = int(input("Please enter a number: "))
break
except ValueError:
print("Oops! That was no valid number. Try again...")
もしもexpect
内にて指定された例外と一致しないエラーが発生すると、その例外はtry
の外側に渡される。外に対するハンドラ (handler、処理部) がどこにもなければ、 処理されない例外 (unhandled exception
) となり、エラーメッセージを出して実行を停止する。
try..expect
はオプションとしてelse
を設けることができる。else
を設ける場合、全てのecpect
より後ろに記述しなくてはならない。
else
はtry
にて全く例外が送出されなかったおきに実行できるコードとして役立つ。
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
例外ハンドラは、try 節 の直接内側で発生した例外を処理するだけではなく、そのtry
節 から (たとえ間接的にでも) 呼び出された関数の内部で発生した例外も処理する。
以下例
def this_fails():
x = 1/0
try:
this_fails()
except ZeroDivisionError as err:
print('Handling run-time error:', err)
Handling run-time error: division by zero
raise
)
8.4. 例外を送出する(
raise
文を使って例外を発生させることが可能。
raise NameError('HiThere')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
raise NameError('HiThere')
NameError: HiThere
raise
の唯一の引数は創出される例外を示す。
これは例外インスタンスや例外クラス(BaseException を継承したクラス、たとえば Exception やそのサブクラス)でなければならない。
8.5. 例外の連鎖
ある例外から直接影響されていることを示すためにraise
のオプションのfrom
を指定する。
raise RuntimeError from exc
def func():
raise ConnectionError
try:
func()
except ConnectionError as exc:
raise RuntimeError('Failed to open database') from exc
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
func()
~~~~^^
File "<stdin>", line 2, in func
ConnectionError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
raise RuntimeError('Failed to open database') from exc
RuntimeError:
finally
8.7. クリーンアップ動作を定義する
try
文にはクリーンアップ動作がある。どんな状況でも必ず実行される
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
>>>
もしfinally
がある場合、try
文が終わる前の最後の処理をfinally
が実行する。
try
が例外を発生させるかに問わずfinally
実行される。
複雑なケース
- もし
try
の実行中に例外が発生したらexpect
によって処理される。もし例外がexpect
により処理されなければfinally
が実行された後にその例外が再送出される。 -
expect
またはelse
にて例外が発生したとする。その場合はfinally
が実行された後に例外が再送出される。 -
finally
内でbreak
,continue
,return
が実行された場合、例外は再創出されない。 - もし
try
文がbreak
,continue
またはreturn
のいずれかに達するとそのbreak
,continue
またはreturn
の直前にfinally
が実行される。 - もし
finally
がreturn
を含む場合、返される値はtry
のreturn
ではなくfinally
のreturn
になる
例
def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
else:
print("result is", result)
finally:
print("executing finally clause")
divide(2, 1)
result is 2.0
executing finally clause
divide(2, 0)
division by zero!
executing finally clause
divide("2", "1")
executing finally clause
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
divide("2", "1")
~~~~~~^^^^^^^^^^
File "<stdin>", line 3, in divide
result = x / y
~~^~~
TypeError: unsupported operand type(s) for /: 'str' and 'str'
上記よりfinally
はどの場合でも実行される。
一番最後の文字列の割り算でTypeError
はexpect
で処理されないため、先にfinally
が実行されたのちに例外が再創出される。
8.9. 複数の関連しない例外の送出と処理
いくつか発生した例外の報告が必要なケースがある。
ExceptionGroup
は例外インスタンスのリストをまとめ、同時に創出できるようにする。
ExceptionGroupも例外のため他の例外と同じように捕捉できる。
def f():
excs = [OSError('error 1'), SystemError('error 2')]
raise ExceptionGroup('there were problems', excs)
f()
+ Exception Group Traceback (most recent call last):
| File "<stdin>", line 1, in <module>
| f()
| ~^^
| File "<stdin>", line 3, in f
| raise ExceptionGroup('there were problems', excs)
| ExceptionGroup: there were problems (2 sub-exceptions)
+-+---------------- 1 ----------------
| OSError: error 1
+---------------- 2 ----------------
| SystemError: error 2
+------------------------------------
try:
f()
except Exception as e:
print(f'caught {type(e)}: e')
caught <class 'ExceptionGroup'>: e
ExceptionGroupの例外の処理
expect*
節で処理する方法
パターン1 ExceptionGroupでまとめられている個々の例外をtry:
# ExceptionGroup例外を送出するコード
except* TypeError as e:
# ExceptionGroup例外に格納されているTypeError例外を処理
except* ValueError as e:
# ExceptionGroup例外に格納されているValueError例外を処理
パターン2 ExceptionGroup全体をまとめて処理する方法
try:
# ExceptionGroup例外を送出するコード
except ExceptionGroup as eg:
# ExceptionGroup例外に格納されている例外を個別に取り出して処理する
9 クラス
9.2. Python のスコープと名前空間
名前空間(ネームスペース)とは名前からオブジェクトへの対応づけのことを指す。
属性という言葉は.
に続く名前全てに対して使っている。
例えば式z.real
でreal
はオブジェクトz
の属性。
名前空間はさまざまな時点で作成され、寿命もさまざま。
9.2.1. スコープと名前空間の例
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)
出力結果
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
do_local()
...スコープ:do_local
関数内
do_nonlocal()
...スコープ:do_nonlocal
...scope_test
関数内
do_global()
...スコープ:モジュールレベル
9.3.1. クラス定義の構文
クラス定義の単純な形式
class ClassName:
<statement-1>
.
.
.
<statement-N>
9.3.2. クラスオブジェクト
クラスオブジェクトは2種類の演算、属性参照とインスタンス生成をサポートしている。
属性参照にはobj.name
を使う
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
クラスのインスタンス化には関数記法を使う。クラスオブジェクトのことをクラスの新しいインスタンスを返す引数のない関数のように扱う。
x = MyClass()
上記はクラスの新しいインスタンスを作成し、そのオブジェクトをローカル変数x
へ格納する。
インスタンス化操作ではからのオブジェクトが作成される。多くのクラスは特定の初期状態でカスタマイズされたオブジェクトを作成したい。
そのためクラスには_init_()
という特殊メソッドが定義されている。新しくインスタンス化された際に自動的に_init_()
を呼び出す。
def __init__(self):
self.data = []
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
x = Complex(3.0, -4.5)
x.r, x.i
(3.0, -4.5)
9.3.3. インスタンスオブジェクト
インスタンオブジェクトでできる操作は属性の参照。有効な属性名はデータ属性とメソッドの2種類がある。
データ属性
x.counter = 1
while x.counter < 10:
x.counter = x.counter * 2
print(x.counter)
del x.counter
9.3.4. メソッドオブジェクト
メソッドとはオブジェクトの属するメソッドのこと
x.f()
xf = x.f
while True:
print(xf())
メソッドが呼び出された時、実際には何が起きているか?
f()
の関数定義では引数を一つ指定していたにも関わらず上記ではx.f()
にて引数なしで呼び出されている。
なぜ呼び出せるかというと引数にインスタンスオブジェクトが渡されるため
x.f()
という呼び出しはMyClass.f(x)
と等価である。
9.3.5. クラスとインスタンス変数
以下コードは間違い
tricks
がクラス変数として扱われ、別の犬間で同じtricks
が共有されてしまうため。
class Dog:
tricks = [] # クラス変数の間違った使用
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks # 意図せず すべての犬で共有
['roll over', 'play dead']
以下正しい例
class Dog:
def __init__(self, name):
self.name = name
self.tricks = [] # 犬ごとに新しい空リストを作る
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
9.4. いろいろな注意点
以下ではf
,g
,h
は全てC
の属性であり,関数オブジェクトを参照している。
全てC
のインスタンスメソッドである。
# クラス外で定義された関数
def f1(self, x, y):
return min(x, x+y)
class C:
f = f1
def g(self):
return 'hello world'
h = g
メソッドはself
引数のメソッド属性を使って他のメソッドを呼び出すことができる
class Bag:
def __init__(self):
self.data = []
def add(self, x):
self.data.append(x)
def addtwice(self, x):
self.add(x)
self.add(x)
9.5. 継承
Python には継承に関係する 2 つの組み込み関数がある
-
isinstance()
を使うとインスタンスの型が調べられる。- isinstance(obj, int) は
obj.__class__
がint
やint
の派生クラスの場合に限りTrue
になります。
- isinstance(obj, int) は
-
issubclass()
を使うと継承関係が調べられる。- bool は int のサブクラスなので
issubclass(bool, int)
はTrue
です。しかし、float
はint
のサブクラスではないのでissubclass(float, int)
はFalse
です。
- bool は int のサブクラスなので
9.6. プライベート変数
オブジェクトの中からしかアクセス出来ない "プライベート" インスタンス変数は、 Python にはありません。しかし、ほとんどの Python コードが従っている慣習があります
しかしアンダースコアで始まる名前は非publicなものとして扱う慣習がある。ex)_spam
名前マングリングは、サブクラスが内部のメソッド呼び出しを壊さずにオーバーライドするのに便利。
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # 元の update() メソッドのプライベートコピー
class MappingSubclass(Mapping):
def update(self, keys, values):
# update() への新シグネチャ導入
# しかし __init__() は壊さない
for item in zip(keys, values):
self.items_list.append(item)
上記ではもしMappingSubClass
に__update
識別子を導入しても機能する。
Mapping
クラスでは_Mapping__update
となり_MappingSubclass__update
にそれぞれ置き換えるからである。
@dataclass
)
9.7. 残りのはしばし(
名前つきのデータ要素をひとまとめにするデータ方dataclasses
from dataclasses import dataclass
@dataclass
class Employee:
name: str
dept: str
salary: int
john = Employee('john', 'computer lab', 1000)
john.dept
'computer lab'
john.salary
1000
9.8. イテレータ (iterator)
イテラブルとイテレータに関して
イテラブルとは
for文で要素を一つずつ取り出せるような反復可能なオブジェクトのこと
- シーケンス型(リスト、タプル、range)
- マッピング型(辞書)
- テキストシーケンス型(文字列)
- バイナリシーケンス型(bytes、bytearray、memoryview)
イテレータに関して
型の一つで順番に要素を取得できるオブジェクトのこと
9.9 ジェネレータ
ジェネレータはイテレータを作成するためのツール
ジェネレータは通常の関数のように書かれるが何らかのデータを返す際にはyield
を使う
以下例
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
for char in reverse('golf'):
print(char)
f
l
o
g
9.10. ジェネレータ式
リスト内包表記のように書くが[]
ではなく()
で囲むのが特徴
ジェネレータ式は完全なジェネレータの定義よりコンパクトですが、ちょっと融通の効かないところがあります。 同じ内容を返すリスト内包表記よりはメモリに優しいことが多いという利点があります。
sum(i*i for i in range(10)) # 平方和
285
xvec = [10, 20, 30]
yvec = [7, 5, 3]
sum(x*y for x,y in zip(xvec, yvec)) # ドット積
260
10. 標準ライブラリミニツアー
10.3. コマンドライン引数
sys
# File demo.py
import sys
print(sys.argv)
上記を以下のように実行
$ python demo.py one two three
出力結果
$ ['demo.py', 'one', 'two', 'three']
argparse
コマンドライン引数を処理するための機能
import argparse
parser = argparse.ArgumentParser(
prog='top',
description='Show top lines from each file')
parser.add_argument('filenames', nargs='+')
parser.add_argument('-l', '--lines', type=int, default=10)
args = parser.parse_args()
print(args)
上記を以下のように実行
$ python top.py --lines=5 alpha.txt beta.txt
結果は以下
args.lines
を5
、args.filenames
を ['alpha.txt', 'beta.txt']
に設定。
10.5. 文字列のパターンマッチング
import re
re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
# ['foot', 'fell', 'fastest']
re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
# 'cat in the hat'
上記解説
-
re.findall
...指定された式表現に一致する部分文字列をリストとして返す。-
r'\bf[a-z]*'
-
\b
単語の境界を表す -
f
...f
にマッチするか -
[a-z]*
小文字のアルファベット全体にマッチするか(f
)で始まる文字列全体
-
-
-
re.sub
...指定された正規表現に一致する文字列を指定された文字列に置き換えます-
r'(\b[a-z]'
...一文字以上からなる単語を認識 -
+) \1
...最初に正規表現にて認識した単語の同じ文字列をマッチさせる。 -
r'\1'
...第二引数の置き換え文字列最初に認識した単語へ置き換え
-
つまり上記場合、全単語を調べる上でthe the
を認識し、1個目に認識したthe
へ置き換える。
10.7. インターネットへのアクセス
インターネットにアクセスしたりインターネットプロトコルを処理したりするための多くのモジュールがあります。最も単純な2つのモジュールは、 URL からデータを取得するための urllib.request と、メールを送るための smtplib です
urllib.request
from urllib.request import urlopen
with urlopen('http://worldtimeapi.org/api/timezone/etc/UTC.txt') as response:
for line in response:
line = line.decode() # Convert bytes to a str
if line.startswith('datetime'):
print(line.rstrip()) # Remove trailing newline
smtplib
import smtplib
server = smtplib.SMTP('localhost')
server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
"""To: jcaesar@example.org
From: soothsayer@example.org
Beware the Ides of March.
""")
server.quit()
10.9. データ圧縮
import zlib
s = b'witch which has which witches wrist watch'
len(s)
41
threading
)
11.4. マルチスレッディング(
スレッド処理 (threading) とは、順序的な依存関係にない複数のタスクを分割するテクニックです。スレッドは、ユーザの入力を受け付けつつ、背後で別のタスクを動かすようなアプリケーションの応答性を高めます。同じような使用例として、I/O を別のスレッドの計算処理と並列して動作させるというものがあります。
import threading, zipfile
class AsyncZip(threading.Thread):
def __init__(self, infile, outfile):
threading.Thread.__init__(self)
self.infile = infile
self.outfile = outfile
def run(self):
f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print('Finished background zip of:', self.infile)
background = AsyncZip('mydata.txt', 'myarchive.zip')
background.start()
print('The main program continues to run in foreground.')
background.join() # Wait for the background task to finish
print('Main program waited until background was done.')
-
class AsyncZip(threading.Thread):
を継承してAsyncZip
クラスを作成 -
__init__
...入出力ファイルを設定、threading.Thread.
スーパークラスのコンストラクタを作成 -
def run(self):
にてzipファイル作成と作成完了のログを出す設定 -
background = AsyncZip('mydata.txt', 'myarchive.zip') background.start()
にてインスタンス作成とスレッド作成-
background.start()
にてrun()
が走る
-
-
background.join() print('Main program waited until background was done.')
にてメインスレッドの処理待ちその後ログ出力
11.7. リスト操作のためのツール
array
from array import array
a = array('H', [4000, 10, 700, 22222])
sum(a)
26932
a[1:3]
array('H', [10, 700])
-
arrray(typecode, イテレータ)
-
typecode
...配列内のデータ型を指定する1文字のコード。-
H
...符号なし2バイト
-
- イテレータ...配列の初期値となるリストやタプルなどのシーケンス。
-
collections.deque
collections モジュールでは、 deque オブジェクトを提供しています。リスト型に似ていますが、データの追加と左端からの取り出しが速く、その一方で中間にある値の参照は遅くなります。こうしたオブジェクトはキューや木構造の幅優先探索の実装に向いています
from collections import deque
d = deque(["task1", "task2", "task3"])
d.append("task4")
print("Handling", d.popleft())
Handling task1
- d.popleft()
にて左端の要素を取り出しそれ以外を削除
11.8. 10進浮動小数演算
decimal モジュールでは、 10 進浮動小数の算術演算をサポートする Decimal データ型を提供しています
例えば、70 セントの電話代にかかる 5% の税金を計算しようとすると、10 進の浮動小数点値と 2 進の浮動小数点値では違う結果になってしまいます。計算結果を四捨五入してセント単位にしようとすると、以下のように違いがはっきり現れます
from decimal import *
round(Decimal('0.70') * Decimal('1.05'), 2)
Decimal('0.74')
round(.70 * 1.05, 2)
0.73
上の例で、Decimal を使った計算では、末尾桁のゼロが保存されており、有効数字2桁の被乗数から自動的に有効数字を 4 桁と判断しています。Decimal は手計算と 同じ方法で計算を行い、2 進浮動小数が 10 進小数成分を正確に表現できないことに よって起きる問題を回避しています。
12. 仮想環境とパッケージ
12.1. はじめに
Pythonアプリケーションは特定のライブラリやそのバージョンを必要とすることが多く、異なるアプリケーション間でライブラリのバージョン要求が衝突することがあります。この問題を解決するために 仮想環境 を使用します。
仮想環境は、特定のPythonバージョンと追加パッケージを含む独立した環境を提供し、各アプリケーションがそれぞれの環境で必要なライブラリを自由に管理できます。これにより、ライブラリのバージョン変更が他のアプリケーションに影響を与えることを防ぎます。
12.2. 仮想環境の作成
以下のようにして仮想環境を作成可能
$ python -m venv tutorial-env{仮想環境名}
これは tutorial-env ディレクトリがなければ作成して、その中に Python インタプリタ、その他関連するファイルのコピーを含むサブディレクトリを作る。
仮想環境を作成後、有効か
$ source tutorial-env/bin/activate
有効化し、Pythonを実行するとその仮想環境のPythonを実行化するようになる。
$ source ~/envs/tutorial-env/bin/activate
(tutorial-env) $ python
Python 3.5.1 (default, May 6 2016, 10:59:36)
...
>>> import sys
>>> sys.path
['', '/usr/local/lib/python35.zip', ...,
'~/envs/tutorial-env/lib/python3.5/site-packages']
仮想環境を無効化は以下
$ deactivate
12.3. pip を使ったパッケージ管理
pip と呼ばれるプログラムでパッケージをインストール、アップグレード、削除することができます。デフォルトでは pip は Python Package Index からパッケージをインストールします。
ブラウザを使って Python Package Index を閲覧することができます。
(tutorial-env) $ python -m pip install novas
Collecting novas
Downloading novas-3.1.1.3.tar.gz (136kB)
Installing collected packages: novas
Running setup.py install for novas
Successfully installed novas-3.1.1.3
バージョンの指定
パッケージ名のあとに == とバージョン番号を付けることで、特定のバージョンのパッケージをインストールすることもできる。
(tutorial-env) $ python -m pip install requests==2.6.0
Collecting requests==2.6.0
Using cached requests-2.6.0-py2.py3-none-any.whl
Installing collected packages: requests
Successfully installed requests-2.6.0
python -m pip show
...指定されたパッケージの情報を表示
(tutorial-env) $ python -m pip show requests
---
Metadata-Version: 2.0
Name: requests
Version: 2.7.0
Summary: Python HTTP for Humans.
Home-page: http://python-requests.org
Author: Kenneth Reitz
Author-email: me@kennethreitz.com
License: Apache 2.0
Location: /Users/akuchling/envs/tutorial-env/lib/python3.4/site-packages
Requires:
python -m pip list
...仮想環境にインストールされた全てのパッケージを表示。
(tutorial-env) $ python -m pip list
novas (3.1.1.3)
numpy (1.9.2)
pip (7.0.3)
requests (2.7.0)
setuptools (16.0)
requirements.txt
...バージョン管理システムにコミットして、アプリケーションの一部として配布することができます。ユーザーは必要なパッケージをpip install -r
でインストールできる。
(tutorial-env) $ python -m pip install -r requirements.txt
Collecting novas==3.1.1.3 (from -r requirements.txt (line 1))
...
Collecting numpy==1.9.2 (from -r requirements.txt (line 2))
...
Collecting requests==2.7.0 (from -r requirements.txt (line 3))
...
Installing collected packages: novas, numpy, requests
Running setup.py install for novas
Successfully installed novas-3.1.1.3 numpy-1.9.2 requests-2.7.0
Discussion