リストである data というメンバーを持つクラスがあるとします。
たとえば、ファイル名 (リストを初期化するためのデータを含む) または実際のリストを使用してクラスを初期化できるようにしたいと考えています。
これを実現するためのテクニックは何ですか?
見てタイプを確認するだけですか__class__
?
何か見逃しているトリックがあるのでしょうか?
私は引数の型によるオーバーロードが簡単な C++ に慣れています。
ベストアンサー1
「代替コンストラクター」を取得するより簡単な方法は、クラスメソッドを使用することです。たとえば、次のようになります。
>>> class MyData:
... def __init__(self, data):
... "Initialize MyData from a sequence"
... self.data = data
...
... @classmethod
... def fromfilename(cls, filename):
... "Initialize MyData from a file"
... data = open(filename).readlines()
... return cls(data)
...
... @classmethod
... def fromdict(cls, datadict):
... "Initialize MyData from a dict's items"
... return cls(datadict.items())
...
>>> MyData([1, 2, 3]).data
[1, 2, 3]
>>> MyData.fromfilename("/tmp/foobar").data
['foo\n', 'bar\n', 'baz\n']
>>> MyData.fromdict({"spam": "ham"}).data
[('spam', 'ham')]
これがすっきりしている理由は、期待される型について疑いの余地がなく、呼び出し元が渡したデータ型で何をするつもりなのかを推測する必要がないからです。 の問題は、isinstance(x, basestring)
呼び出し元が、たとえば型が基本文字列ではないとしても、それを文字列として扱うべきである (別のシーケンスではない) と伝える方法がないことです。 また、呼び出し元は、同じ型を異なる目的で使用したい場合もあり、時には単一の項目として、時には項目のシーケンスとして使用したい場合もあります。 明示的にすることで、すべての疑問が解消され、より堅牢で明確なコードになります。