384

リストであるデータと呼ばれるメンバーを持つクラスがあるとしましょう。

たとえば、ファイル名(リストを初期化するためのデータを含む)または実際のリストでクラスを初期化できるようにしたいと考えています。

これを行うためのあなたのテクニックは何ですか?

を見て型を確認するだけ__class__ですか?

私が見逃しているかもしれないトリックはありますか?

私は、引数の型によるオーバーロードが簡単な C++ に慣れています。

4

10 に答える 10

513

「代替コンストラクター」を取得するより適切な方法は、クラスメソッドを使用することです。例えば:

>>> 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)は、たとえば、型がベース文字列ではなくても、それを文字列として (別のシーケンスではなく) 扱う必要があることを呼び出し元が伝える方法がないことです。同じタイプを異なる目的に使用します。単一のアイテムとして使用することもあれば、一連のアイテムとして使用することもあります。明示的であることですべての疑念が取り除かれ、より堅牢で明確なコードにつながります。

于 2008-09-26T20:30:15.857 に答える
41

素晴らしい質問です。私もこの問題に取り組みました。「ファクトリ」(クラス メソッド コンストラクター) が良い方法であることに同意しますが、非常に役立つ別の方法を提案したいと思います。

以下にサンプルを示します (これはreadコンストラクターではなくメソッドですが、考え方は同じです)。

def read(self, str=None, filename=None, addr=0):
    """ Read binary data and return a store object. The data
        store is also saved in the interal 'data' attribute.

        The data can either be taken from a string (str 
        argument) or a file (provide a filename, which will 
        be read in binary mode). If both are provided, the str 
        will be used. If neither is provided, an ArgumentError 
        is raised.
    """
    if str is None:
        if filename is None:
            raise ArgumentError('Please supply a string or a filename')

        file = open(filename, 'rb')
        str = file.read()
        file.close()
    ...
    ... # rest of code

ここでの重要なアイデアは、名前付き引数に対する Python の優れたサポートを使用してこれを実装することです。ここで、ファイルからデータを読み取りたい場合は、次のように言います。

obj.read(filename="blob.txt")

文字列から読み取るには、次のように言います。

obj.read(str="\x34\x55")

このようにして、ユーザーは呼び出すメソッドを 1 つだけ持つことができます。ご覧のとおり、内部での処理はそれほど複雑ではありません

于 2008-10-17T13:34:31.393 に答える
14

迅速で汚い修正

class MyData:
    def __init__(string=None,list=None):
        if string is not None:
            #do stuff
        elif list is not None:
            #do other stuff
        else:
            #make data empty

次に、それを呼び出すことができます

MyData(astring)
MyData(None, alist)
MyData()
于 2012-04-18T21:38:33.850 に答える
9

より良い方法は、isinstance と型変換を使用することです。私があなたを正しく理解しているなら、あなたはこれが欲しい:

def __init__ (self, filename):
    if isinstance (filename, basestring):
        # filename is a string
    else:
        # try to convert to a list
        self.path = list (filename)
于 2008-09-26T19:52:59.193 に答える
4

isinstance を使用する必要があります

isinstance(...)
    isinstance(object, class-or-type-or-tuple) -> bool

    Return whether an object is an instance of a class or of a subclass thereof.
    With a type as second argument, return whether that is the object's type.
    The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
    isinstance(x, A) or isinstance(x, B) or ... (etc.).
于 2008-09-26T19:54:33.290 に答える
2

おそらくisinstance組み込み関数が必要です:

self.data = data if isinstance(data, list) else self.parse(data)
于 2008-09-26T19:54:30.843 に答える
-1

OK、素晴らしい。この例をファイル名ではなくタプルと組み合わせただけですが、それは簡単です。皆さんありがとう。

class MyData:
    def __init__(self, data):
        self.myList = []
        if isinstance(data, tuple):
            for i in data:
                self.myList.append(i)
        else:
            self.myList = data

    def GetData(self):
        print self.myList

a = [1,2]

b =(2,3)

c = MyData(a)

d = MyData(b)

c.GetData()

d.GetData()

[1、2]

[2、3]

于 2008-09-26T20:18:19.397 に答える
-1

私の好ましい解決策は次のとおりです。

class MyClass:
    _data = []
    __init__(self,data=None):
        # do init stuff
        if not data: return
        self._data = list(data) # list() copies the list, instead of pointing to it.

MyClass()次に、またはで呼び出しますMyClass([1,2,3])

それが役立つことを願っています。ハッピーコーディング!

于 2014-09-24T13:55:57.867 に答える
-1

もっとPythonicに行ってみませんか?

class AutoList:
def __init__(self, inp):
    try:                        ## Assume an opened-file...
        self.data = inp.read()
    except AttributeError:
        try:                    ## Assume an existent filename...
            with open(inp, 'r') as fd:
                self.data = fd.read()
        except:
            self.data = inp     ## Who cares what that might be?
于 2014-05-01T19:49:07.790 に答える