5

サンプルコードは次のようになります。

def assign(self, input=None, output=None, param=None, p1=None, p2=None):
    if input:
        self.input = input
    if output:
        self.output = output
    if param:
        self.param = param
    if p1:
        self.p1 = p1
    if p2:
        self.p2 = p2

これは非常に明確に見えますが、この関数に 10 個のパラメーターがあると問題が発生します。誰もこれのためのより便利な方法についてのアイデアを持っていますか?

4

4 に答える 4

7

次のようなことができます:

def assign(self,**kwargs):
    for k,v in kwargs.items():
        if v:
           setattr(self,k,v)

これは非常にシンプルで、多くの状況に適しています。受け入れて TypeError を発生させる一連のキーワードを維持したい場合は、次のようにします。

#python2.7 and newer
def assign(self,allowed_kwargs={'foo','bar','baz'},**kwargs):
    if kwargs.keysview() - allowed_kwargs:
        raise TypeError('useful message here...')
    for k in allowed_kwargs:
        setattr(self,k,kwargs[k])

ユーザーは許可された kwargs のセットを確認できるため、これもある程度検査可能です。

于 2013-03-10T02:34:23.377 に答える
1

明示的は暗黙的よりも優れています

def assign(self, input=None, output=None, param=None, p1=None, p2=None):

~に比べて多くの利点がある

def assign(self, **kwargs)
  • 自己記録です
  • TypeErrorに無効なパラメータが渡された場合、help が発生し ますassign
  • assign位置引数とキーワード引数で呼び出すことができます

その名誉のために、OPが投稿したコードは完全に明示的ですが、ifステートメントは単調です。単調さを減らすために、次のようなものを使用できます。

class Foo(object):
    def assign(self, input=None, output=None, param=None, p1=None, p2=None):
        for name in 'input output param p1 p2'.split():
            val = vars()[name]
            if val is not None:
                setattr(self, name, val)

foo = Foo()
foo.assign(p1=123, p2='abc')
于 2013-03-10T02:39:12.147 に答える
0

Python の優れた点の 1 つは、その対話型インタープリターです。次のようなコードを書くと:

>>> def assign(self, input=None, output=None, param=None, p1=None, p2=None):
...     pass
... 

関数の使用方法を理解するのは非常に簡単です。

>>> help(assign)
Python Library Documentation: function assign in module __main__

assign(self, input=None, output=None, param=None, p1=None, p2=None)

比較すると:

>>> def assign2(self, **kwargs):
...     pass
... 

与えます:

>>> help(assign2)
Python Library Documentation: function assign2 in module __main__

assign2(self, **kwargs)

最初の形式が望ましい理由を理解していただければ幸いです。ただし、すべてを 2 回 (引数と本文で) 記述することは避けたいと考えています。

最初の質問は、なぜこのような性質のコードを書いているのですか? 持ち運ぶ属性のヒープを持つクラスが必要になるのは非常に一般的なケースですが、これらの属性のセットは基本的に固定されています。最も一般的なケースでは、これらの属性はオブジェクトの存続期間中は変更されません。その場合、python にはまさにそのためのヘルパーが組み込まれています。

>>> import collections
>>> Assignment = collections.namedtuple('Assignment', 'input output param p1 p2')
>>> assign = Assignment(None, None, None, None, None)._replace
>>> assign(p1=10)
Assignment(input=None, output=None, param=None, p1=10, p2=None)
>>> help(Assignment)
Python Library Documentation: class Assignment in module __main__

class Assignment(__builtin__.tuple)
 |  Assignment(input, output, param, p1, p2)
 |  
... SNIP

namedtupleは通常のクラスであり、それらを継承して特別な動作を与えることができます。残念ながら、それらは不変であり、それが必要になった場合は、別の手法が必要になります。ただし、ほとんどの場合、最初に名前付きタプルに到達する必要があります。それ以外の場合は、他の魔法を利用できます。関数の開始時に引数のみを含むすべてのローカル変数を取得できます。

>>> class Assignable(object):
...     def assign(self, input=None, output=None, param=None, p1=None, p2=None):
...         _kwargs = vars()
...         _kwargs.pop('self')
...         vars(self).update((attr, value) for attr, value in _kwargs.items() if value is not None)
... 
>>> a = Assignable()
>>> vars(a)
{}
>>> a.assign(p1=6)
>>> vars(a)
{'p1': 6}
>>> a.p1
6

そしてhelp()テキストはまだ非常に役に立ちます!

>>> help(a.assign)
Python Library Documentation: method assign in module __main__

assign(self, input=None, output=None, param=None, p1=None, p2=None) method of __main__.Assignable instance
于 2013-03-10T13:51:51.300 に答える
0

mgilson と unutbu のソリューションでは、すべてのタイプの呼び出しを作成する可能性が失われます。

私の次の解決策では、この可能性が保持されます。

class Buu(object):
    def assign(self,
               input=None, output=None,
               param=None,
               p1=None, p2=None,
               **kw):
        for k,v in locals().iteritems():
            if v not in (self,None,kw):
                if v == (None,):
                    setattr(self,k,None)
                else:
                    setattr(self,k,v)
        for k,v in kw.iteritems():
            setattr(self,k,v)

buu = Buu()

buu.assign(None,(None,), p1=[])
print "buu's attributes:",vars(buu)
print

buu.assign(1,p2 = 555, xx = 'extra')
print "buu's attributes:",vars(buu)

結果

buu's attributes: {'output': None, 'p1': []}

buu's attributes: {'p2': 555, 'output': None, 'xx': 'extra', 'p1': [], 'input': 1}

ちなみに、コーダーがパラメーターのデフォルト引数として置くとき、それは、実行中に実際に影響を与える重要な引数としてNone渡す必要がある場合はないと予測しているからです。したがって、真の有意な引数として渡す点は、誤った問題 だと思います。ただし、上記のコードでは、値を持つ新しい属性を作成する必要がある場合は、引数を にする という規則を使用することで、この問題を回避しています。 None
None
None(None,)

誰かが合格したい場合(None,)???
真剣に ?
なんてこった!

于 2013-03-10T22:05:07.187 に答える