2012-04-30 13 views
2

defaultdictと類推してdefaultlistを作成しようとしています。そのアイデアは、値が明示的に設定されていないすべてのインデックスで、いくつかの要素があらかじめ入力されているリスト(実際には!)が必要な場合があるということです。 defaultdictとの違いは、ユーザー割り当てのためにリストを拡張しなければ、リストにデフォルト値を実際に追加しないということです。defaultlist design

1)このデザインに問題はありますか?

2)これは私が使用する実装です。それに問題はありますか?

class defaultlist(list): 
    def __init__(self, default_factory, arg =()): 
    # note: cannot use arg = None since list(None) is not the same as list() 
    # alternatively can use: 
    # def __init__(self, default_factory, *args, **kwargs) 
    self.default_factory = default_factory 
    super().__init__(arg) 

    def __getitem__(self, key): 
    try: 
     return super().__getitem__(key) 
    except IndexError: 
     return self.default_factory() 

    def __setitem__(self, key, value): 
    for i in range(len(self), key): 
     self.append(self.default_factory()) 
    self.append(value) 

EDIT:もともと、私は2つの間違いがありました。申し訳ありませんが、答えに両方のエラーを指摘してくれてありがとう。

+0

なぜあなただ​​けの数字キーでdefaultdictを使用することはできませんか? – Keith

+1

@Keith:なぜPythonは数値キーで 'dict'を使い、言語の厄介な' list'を投げ捨てるのですか? –

+0

@EliBenderskyあなたのアプリケーションがある種の順序付けられたシーケンスを維持する必要があるかどうかによって異なります。それが本当に必要条件であるかどうかは、この疑問からは明らかではありません。 – Keith

答えて

3

問題。

  1. __init__関数は、すべての引数を基本クラスに転送しようとします。しかし、あなたがそれを書いている方法は1つの引数だけを送ることができ、コンストラクタは常に第2引数を期待します。 - rangeが最後に排他的であることに注意してください - それゆえ

    def __init__(self, default_factory, *args, **kwargs): 
        super().__init__(*args, **kwargs) 
        self.default_factory = default_factory 
    
  2. __setitem__機能は、すべての未既存のインデックスを埋めるためにしようとしますが、あなたはkey自体が見逃している:Pythonであることを行うための適切な方法super().__setitem__メソッドは失敗します。その場合は.appendを使用してください。あなたが解決策の近くにある

    def __setitem__(self, key, value): 
        try: 
         super().__setitem__(key, value) 
        except IndexError: 
         for i in range(len(self), key): 
          self.append(self.default_factory()) 
         self.append(value) 
    
+0

re:1 - ここでは複数の議論が期待されています。'list'は引数が1つしかないので、* argsと** kwargsはおそらく必要ありません。しかし、あなたは、コンストラクタが常に第2引数を期待していることが問題になる可能性があります。これはargにデフォルト値を与えることで簡単に解決できます。 – weronika

+0

@weronika:はい、そうです - いずれかの方法で動作します(デフォルトまたは* args/** kwargs)。 – max

+0

@KennyTM:はい、ありがとう。 – max

2

私はあなたのTypeErrorの理由は、あなたが「def defaultlist(list):」行でdef代わりのclassを使用だけということなので、defaultlistは機能ではなく、クラスのように扱われていると思います。

+0

ああありがとう、私はあまりにも疲れています... – max

1

。スーパービルトイン関数の使用と、引数のパッキングが動作する方法を混在させています。 (NBは:@weronikaが指摘したように、あなたが代わりにクラスのDEFとあなたの質問にタイプミスを得たが、お使いのエラーメッセージがクラスでテストされているあなたのコードから来ている)

これを試してみてください:

class defaultlist(list): 
    def __init__(self, default_factory, arg =()): 
    super(defaultlist, self).__init__(arg) 
    self.default_factory = default_factory 

    def __getitem__(self, key): 
    try: 
     return super(defaultlist, self).__getitem__(key) 
    except IndexError: 
     return self.default_factory() 

    def __setitem__(self, key, value): 
    for i in range(len(self), key): 
     self.append(self.default_factory()) 
    super(defaultlist, self).__setitem__(key, value) 

lst = defaultlist(int, [3, 4, 5]) 
+0

私はOPのバージョンの引数をアンパックするのに間違っているとは思っていません - 'list 'が通常引数を取る方法を真似た' defaultlist(int、[3,4,5]) 'ですから、 'defaultlist(int、3,4,5)'の方が望ましいと言えます。あなたは 'super()'がうまくいきません。 – weronika

+0

@weronikaが合意したので、あなたの発言を反映するように私の答えを変更しました。 – Boud

0

があります別の問題です。例えば、あなたがリストのデフォルトリストを持っていることを望むならば。 __getitem__(..)の実装は新しいリストを返しますが、defaultlistには格納しません。

この問題を回避するには、この回答では、たとえば、明らかである:https://stackoverflow.com/a/8749640/1143274

関連する問題