概要
初めてのPythonの備忘録です. 学んだことを随時追記していきます.
2018/4/2 追記
当初は身についてないことなどを整理する意味も兼ねて書いていました.
しかし文量が多すぎるので私が理解するのに時間がかかったところ, 書籍のコードでエラーをはいたところ, を備忘録として残すことにしました.
環境/参考資料
- MacOS Sierra v10.12.6
- Python 3.5.2(Anaconda 4.1.1)
- 初めてのPython 第3版
- Pythonドキュメント
5 数値
5.3 数値の使用例
5.3.7 16進数と8進数
16進数は先頭に0x
, 8進数は先頭に0o
をつけます.
In [1]: 0o01, 0o010, 0o0100
Out[1]: (1, 8, 64)
In [2]: 0x01, 0x10, 0xff
Out[2]: (1, 16, 255)
6 ダイナミックな型付け
6.2 共有リファレンス
6.2.2 「同等」と「同一」
- ==演算子はオブジェクトが同等か比較するためのものです.
- is演算子はオブジェクトが同一か比較するためのものです.
わかりにくいので実際に見てみます.
In [32]: L = [1, 2, 3]
In [33]: M = L
In [34]: L == M
Out[34]: True
In [35]: L is M
Out[35]: True
In [36]: L = [1, 2, 3]
In [37]: M = [1, 2, 3]
In [38]: L == M
Out[38]: True
In [39]: L is M
Out[39]: False
つまりL
とM
のオブジェクトが同じなら同等, リファレンスが同じなら同一ということです.
ただし同様のことを小さい数値に対して行うと, 結果が異なる場合があります.
In [40]: x = 42
In [41]: y = 42
In [42]: x == y
Out[42]: True
In [43]: x is y
Out[43]: True
小さい数値や文字列はキャッシュされ再利用されるためです.
あるオブジェクトにいくつのリファレンスがあるか確認した場合は, getrefcount関数を使います.
In [1]: import sys
# オブジェクト42へのリファレンスの数
In [2]: sys.getrefcount(42)
Out[2]: 21
# 新たにオブジェクト42へのリファレンスを追加
In [3]: x = 42
# 新たに追加したので22を返します.
In [4]: sys.getrefcount(42)
Out[4]: 22
9 タプル, ファイルオブジェクト, その他
9.2 ファイル
9.2.3 ファイルオブジェクトの使用例
pickleによりオブジェクトをそのままファイルに保存する
pickleモジュールを使用すれば, Pythonのあらゆるオブジェクトを文字列に変換することなくファイルに直接保存できます.
なおpickleモジュールは, Python2とPython3で仕様が変わったようです. ここではPython3での使用例を示します.
In [1]: F = open('datafile.txt', 'wb')
In [2]: import pickle
In [3]: D = ['spma', 10, [1, 2], {'a': 1, 'b': 2}]
# pickleを利用してオブジェクトDをファイルに保存
In [4]: pickle.dump(D, F)
In [5]: F.close()
In [8]: F = open('datafile.txt', 'rb')
# ファイルからオブジェクトを取り出す
In [9]: E = pickle.load(F)
In [10]: E
Out[10]: ['spma', 10, [1, 2], {'a': 1, 'b': 2}]
# バイトストリーム形式のデータ
In [12]: open('datafile.txt', 'rb').read()
Out[12]: b'\x80\x03]q\x00(X\x04\x00\x00\x00spmaq\x01K\n]q\x02(K\x01K\x02e}q\x03(X\x01\x00\x00\x00bq\x04K\x02X\x01\x00\x00\x00aq\x05K\x01ue.'
11 代入ステートメント, 式ステートメント, printステートメント
11.3 printステートメント
11.3.3 >>を使用したリダイレクト
sys.stdout
に対応するオブジェクトを変更することで出力テキストをリダイレクトする手法はよく用いられます.
しかしこの手法での問題は, 出力先を元の標準出力ストリームに戻したくてもそれが簡単にできない点です.
以下のように工夫することが可能です.
>>> import sys
>>> temp = sys.stdout
>>> sys.stdout = open('log.txt', 'a')
>>> print('spam')
>>> print(1, 2, 3)
>>> sys.stdout.close()
>>> sys.stdout = temp
>>> print('back here')
back here
>>> print(open('log.txt').read())
spam
1 2 3
なお私は簡単なコードの確認にipythonを使っていますが, ipythonだと下記のエラーが出ました.
In [1]: import sys
In [2]: temp = sys.stdout
In [3]: sys.stdout = open('log.txt', 'a')
print('spam')
print(1, 2, 3)
sys.stdout.close()
WARNING:
********
You or a %run:ed script called sys.stdin.close() or sys.stdout.close()!
Exiting IPython!
これは正常な動作のようで, ipythonでsys.stdout.close()
をすると標準出力ストリームでも出力できなくなるようです.
話がそれましたが, 以下の方法で簡単にすることが可能です.
In [1]: log = open('log.txt', 'w')
In [3]: print("1, 2, 3", file=log)
In [4]: print("4, 5, 6", file=log)
In [5]: log.close()
In [6]: print(7, 8, 9)
7 8 9
In [7]: print(open('log.txt').read())
1, 2, 3
4, 5, 6
Python3では>>
は使えません. print("test", file=sys.stdout)
のように出力先をfile
で指定することで同様のことができます.
この方法は標準エラーストリームにエラーメッセージを出力する際によく使用されます.
21 モジュールに関連する高度なテクニック
21.6 相対インポートの構文
fromステートメントで.
を使ってインポートすることもできます. これを明示的な相対インポートといいます.
.
で現在および親パッケージを指定します.
例えば以下のパッケージがあったとします.
- sound/
- __init__.py
- formats/
- __init__.py
- wavread.py
- ...
- effects/
- __init__.py
- echo.py
- surrond.py
- ...
- filters/
- __int__.py
- equalizer.py
- ...
通常インポートする場合は, 以下のようになります.
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
相対インポートの場合, 以下のようになります.
from . import echo
from .. import formats
from ..filters import equalizer
しかしsurround.py
の中でecho.py
を相対インポートした際に以下のエラーがでました.
% python surround.py
Traceback (most recent call last):
File "surround.py", line 1, in <module>
from . import echo
SystemError: Parent module '' not loaded, cannot perform relative import
上記の原因はsuuround.pyがメインモジュールになり, つまり__name__
が__main__
になり__name__.rpartition('.')[0]
が空の文字列を返すためです.
相対インポートできないか試行錯誤しましたが良い方法がみつからなかったので, モジュールサーチパスを設定してインポートをした方が良いと思われます.
24 クラスのコーディング
24.4 演算子のオーバーロード
24.4.4 独自イテレータの作成
ここの例で紹介されているクラスSquares
は自分の環境ではエラーが出て動きませんでした.
next(self)
を__next__(self)
と書き直したらOKでした.
Python3では__next__
をつかうようです.
24.4.5 __getattr__
と__setattr__
記載のクラスempty
はPython3では以下のように変更します.
raise AttributeError, attrname
をraise AttributeError(attrname)
にします.
Python3では上記のようにエラーメッセージは括弧で囲みます.
class empty:
def __getattr__(self, attrname):
if attrname == "age":
return 40
else:
raise AttributeError(attrname)
27 例外の基礎
27.2 例外処理の基本
Python3.0以降ではクラス例外が必須です.
以下のコードはエラーが出ます. class Bad: pass
をclass Bad(Exception): pass
に変更すると動作します.
>>> class Bad: pass
>>> def doomed(): raise Bad()
>>> try:
>>> doomed()
>>> except Bad:
>>> print('got bad')
27.6 raiseステートメント
27.6.2 例外とともにデータを渡す
raiseステートメントで渡されるデータを確認します.
# raisedata.py
def raiser1():
raise Exception("hello")
def raiser2():
raise Exception
def tryer(func):
try:
func()
except Exception as inst:
print('got this:', inst)
実行結果は以下の通りです.
In [1]: from raisedata import *
In [2]: tryer(raiser1)
hello
In [3]: tryer(raiser2)
except節では, 例外名の後に変数を指定することができます. この値は例外インスタンスに結び付けられており, instance.args
に例外インスタンスの引数が入っています.