1. ホーム

Pythonのトラップ:タプルとNonetype

2022-02-24 04:09:20

1. 文字列で生成されるリストの処理にタプルを慎重に使用する

まず、ファイルから一行ずつ読み込んだ文字列を、数字のリストに変換したい。

>>> [float(item) for item in "1e2 to 2".split() if item not in ["to", " "]]
[100.0, 2.0]</span>

そして、ある行を読むと、変換できない "le" があり、エラーが報告されます。

>>> [float(item) for item in "1e2 to 1e".split() if item not in ["to", " "]]

Traceback (most recent call last):
  File "<pyshell#27>", line 1, in <module>
    [float(item) for item in "1e2 to 1e".split() if item not in ["to", " "]]
ValueError: invalid literal for float(): 1e</span>

この例外をキャッチして投げ、エラー文字列の場所を特定し、if文が実行されていないことを発見する。

>>> try:
a = [float(item) for item in "1e2 to 1e".split() if item not in ["to", " "]]
except:
print "error:", a

error: -1e13 to 0.1 1.06148e10 to 1e

読み込まれる文字列は辞書のキーなので、tuple()関数が追加され、文字列は次のように完全に分割されるという不可解な結果になります。

>>> try:
	a = [float(item) for item in "1e2 to 1e".split() if item not in ["to", " "]]
except:
	print "error:", tuple(a)
	
error: ('-', '1', 'e', '1', '3', ' ', 't', 'o', ' ', '0', '.' , '1', ' ', '1', '.' , '0', '6', '1', '4', '8', 'e', '1', '0', ' ', 't', 'o', ' ', '1', 'e', ' ')


テストタプル()

>>> tuple("123")
('1', '2', '3')

View documentation: tuple(iterable) -> iterableのitemから初期化されたタプルです。 これは、tupleが渡されたstrの内容を一つずつメタ祖の内容に読み込んでいくことを意味します となり、上記のような散々な結果になってしまいます。

これは、2つの結果を示しています。

<スパン (1) float()文が失敗した場合、リストは生成されず、文字列の内容がそのままaに代入され、aはstr型となる

>>> try:
	a = [float(item) for item in "1e2 to 1e".split() if item not in ["to", " "]]
except:
	print "error:", type(a),item(a)

error: <type 'str'>

(2) 文字列をリストやtuples()でネストする場合は注意が必要で、一歩間違えると全く違う結果になります。

---------------------------------------------------------------------------------------------

2. ユビキタスなNoneType

タプルの話はさておき、このNoneType()のエラー報告について、上で考えたことのフォローアップをしましょう。

上記で例外をキャッチしているため、プログラムは壊れませんでした。辞書のキーを読み込んだ後、辞書の内容をキー: dic[key].items() で呼び出し、エラーの連鎖が報告されました。

AttributeError: 'NoneType' オブジェクトには 'items' という属性がありません。

<スパン では、Nonetypeとは何でしょうか?

これを理解するには、まずPythonのオブジェクトを理解する必要があります。Pythonのオブジェクトは、ID、タイプ、値という3つのプロパティを持っています。

この3つのプロパティは、オブジェクトの作成時に割り当てられます。変更できるのは値のみで、他は読み取り専用です。また、型自体もオブジェクトです。

NullとNoneはPythonの特殊な型です。Nullオブジェクト、またはNone型は、1つの値、Noneのみを持ちます。

算術演算をサポートせず、組み込みメソッドもありません。 Noneは他のデータ型と比較すると、常にFalseを返します。

Noneは、NoneTypeという独自のデータ型を持っています。Noneを任意の変数にコピーすることはできますが、他のNoneTypeオブジェクトを作成することはできません。

<スパン 一言で言えば NullオブジェクトはNoneTypeとも呼ばれるpythonのオブジェクトで、Noneはこのオブジェクトの値です。

>>> type(None)
<type 'NoneType'>

<スパン <スパン しかし、Nonetypeは全く定義されていません。なぜここでエラーが報告されるのでしょうか?

と思われるのですが、どうなんでしょう。tuples()は文字を分割してしまいますが、少なくともキーは(間違ってはいても)返してくれます。

それからググってみたら、NoneTypeが登場するのは、値も戻り値もない変数や関数を定義しているからで、デフォルトではNoneになるんですね。

例外が発生した後、キーを出力することはできますが、catchによって代入がスキップされるため、キーはまだNoneのままです。


ヒント:float(1e13) = inf