2016-11-30 7 views
3

私は、インスタンス変数でデフォルト値を持つクラスを持っています。Python:プログラムによるクラスインスタンス変数の初期化with localals()

それはself.x = xなどを何度も書くことは非常に冗長なので、私は、プログラムの変数を初期化します。

例:

# The "painful" way 
class A: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.a = a 
     self.b = b 
     self.c = c 
     self.d = d 
     self.e = e 

# The "lazy" way 
class B: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.__dict__.update({k: v for k, v in locals().items() if k!='self'}) 

# The "better lazy" way suggested 
class C: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
      for k, v in locals().items(): 
       if k != 'self': 
        setattr(self, k, v) 

x = A(1, c=7) 
y = B(1, c=7) 
z = C(1, c=7) 

print(x.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(y.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(z.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 

そうするために、この例(持つ、簡潔にするために、わずか5インスタンス変数と任意の方法はを省略)を検討、説明するために

私の人生は簡単に、私はA.

はこの悪い習慣れるのと同じ結果が得られたクラスBに示されているイディオムを使いますか?落とし穴がありますか?

補遺: このイディオムを使用するもう1つの理由は、いくつかのスペースを節約するためだった - 私はMicroPythonでそれを使用するためのもの。 何らかの理由で、Because locals work differently thereは、クラスAで示された方法だけがその中で動作します。

+1

はい。それは悪い習慣です。 'dict()'を使わないのはなぜですか?それらはクラス属性でなければなりませんか? –

+4

関連:http://stackoverflow.com/q/1389180/3001761 – jonrsharpe

+2

私は明らかな落とし穴を考えることはできませんが、私はそれがかなり総体であるとわかります。 – wim

答えて

3

実際にclass Aに示すコードを使用することをお勧めします。あなたが持っているのは繰り返しですコード、冗長コードではなく、繰り返しです常にが悪いです。 __init__を一度だけ書く必要があり、インスタンス変数ごとに1つの割り当てを保持することは、クラスが期待するインスタンス変数の適切な文書(明示的および明示的)です。

でも、注意しなければならないことは、でも異なるパラメータとして初期化できる多くの変数が、クラスを再設計する必要があるというサインである可能性があります。個々のパラメータのいくつかは、個別のリスト、辞書、または追加のクラスにグループ分けされていますか?

+1

Alex Martelliは[stdlibになければならない]と言っています(http://stackoverflow.com/questions/1389180/python-automatically-initialize-instance-variables#comment1230512_1389224)。この繰り返しは避けてください。そして、7年後、何もありません。だから.....¯\\ _(ツ)_ /¯....ここでは、+1があります。 – wim

1

は、より多くのニシキヘビのアプローチを試してみてください。

class C: 
    def __init__(self,a,b=2,c=3,d=4.5,e=5): 
    for k,v in locals().iteritems(): 
     setattr(self,k,v) 
c = C(1) 
print c.a, c.b 
1 2 

このアプローチは、行または2長いかもしれないが、ラインの長さが短くなっている、とあなたの意思あまり複雑。さらに、コードを再利用しようとする人は、期待どおりにオブジェクトの属性にアクセスできます。

これが役に立ちます。

編集:kwargs bcを使用して2番目のアプローチを削除しました。デフォルトの変数要件に対応していません。

重要持ち帰り、ここではあなたの例クラスBが示すように行われていれば、あなたのコードのユーザーが期待どおりにオブジェクトの属性にアクセスすることはできないだろうということです。

+0

'kwargs'はこの場合有用ではありません。すべての必要な変数が渡され、不要な変数が渡されてインスタンス変数として格納されることは保証されません。 – phoibos

+3

2番目の方法では、質問に明白に必要なデフォルトを許可していません。あなたの最初のアプローチでは、あなたの反復から 'self'を除外してください。 – donkopotamus

+0

良い点は、デフォルトが必要な場合は、最初のアプローチを使用してください。 @donkopotamus:setattrは3つの引数を期待しています。最初はオブジェクトのインスタンスである必要があります。クラス定義内で操作する場合、このインスタンスは自己でなければなりません。 –

関連する問題