13

他の2つのクラスから継承するクラスがあります。基本クラスは次のとおりです。

class FirstBase(object):
      def __init__(self, detail_text=desc, backed_object=backed_object,
                   window=window, droppable_zone_obj=droppable_zone_obj,
                   bound_zone_obj=bound_zone_object,
                   on_drag_opacity=on_drag_opacity):
          # bla bla bla

class SecondBase(object):
      def __init__(self, size, texture, desc, backed_object, window):
          # bla bla bla

そしてこれは子供です:

class Child(FirstBase, SecondBase):
       """ this contructor doesnt work
       def __init__(self, **kwargs):
          # PROBLEM HERE
          #super(Child, self).__init__(**kwargs)
       """
       #have to do it this TERRIBLE WAY
       def __init__(self, size=(0,0), texture=None, desc="", backed_object=None,
                    window=None, droppable_zone_obj=[], bound_zone_object=[],
                    on_drag_opacity=1.0):
          FirstBase.__init__(self, detail_text=desc, backed_object=backed_object,
                             window=window, droppable_zone_obj=droppable_zone_obj,
                             bound_zone_obj=bound_zone_object,
                             on_drag_opacity=on_drag_opacity)
          SecondBase.__init__(self, size, texture, desc, backed_object, window)

私はそれをすべてうまく解決したかった**kwargsのですが、最初にコメントアウトされたコンストラクターを呼び出すと、が得られTypeError: __init__() got an unexpected keyword argument 'size'ます。

どうすればそれを機能させることができるか**kwargs?

4

7 に答える 7

19

あなたの問題はsuper、あなたが子クラスでのみ使用しようとしたことです。

super基本クラスでも使用する場合、これは機能します。各コンストラクターは、取るキーワード引数を「食べ」、次のコンストラクターに渡しません。のコンストラクターobjectが呼び出されたときに、キーワード引数が残っていると、例外が発生します。

class FirstBase(object):
    def __init__(self, detail_text=None, backed_object=None,
                 window=None, droppable_zone_obj=None,
                 bound_zone_obj=None, on_drag_opacity=None, **kwargs):
        super(FirstBase, self).__init__(**kwargs)

class SecondBase(object):
    def __init__(self, size=(0,0), texture=None, desc="",
                 backed_object=None, window=None, **kwargs):
        super(SecondBase, self).__init__(**kwargs)

class Child(FirstBase, SecondBase):
    def __init__(self, **kwargs):
        super(Child, self).__init__(**kwargs)

ご覧のとおり、偽のキーワード引数を渡す場合を除いて、機能します。

>>> Child()
<__main__.Child object at 0x7f4aef413bd0>
>>> Child(detail_text="abc")
<__main__.Child object at 0x7f4aef413cd0>
>>> Child(bogus_kw=123)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 14, in __init__
    super(Child, self).__init__(**kwargs)
  File "test.py", line 5, in __init__
    super(FirstBase, self).__init__(**kwargs)
  File "test.py", line 10, in __init__
    super(SecondBase, self).__init__(**kwargs)
TypeError: object.__init__() takes no parameters
于 2012-10-29T15:59:31.317 に答える
3

私はこの解決策が好きではありませんが、あなたはこれを行うことができます:

class FirstBase(object):
  def __init__(self, *args, **kargs):
      kargs.get('karg name', 'default value')
      # bla bla bla

class SecondBase(object):
  def __init__(self, *args, **kargs):
      kargs.get('karg name', 'default value')
      # bla bla bla

class Child(FirstBase, SecondBase):
   def __init__(self, *args, **kargs):
      FirstBase.__init__(self, *args, **kargs)
      SecondBase.__init__(self, *args, **kargs)
于 2012-10-29T16:10:27.697 に答える
1

引数FirstBase.__init__がないからです。引数を追加するsizeか、に追加することができます。size**kwargsFirstBase.__init__

于 2012-10-29T15:50:21.913 に答える
0

このようなことを試してください。

class FirstBase(object):
      def __init__(self, detail_text, backed_object, window, droppable_zone_obj, bound_zone_obj, on_drag_opacity):
          # bla bla bla

class SecondBase(object):
      def __init__(self, texture, desc, backed_object, window, size=None):
          # bla bla bla
于 2012-10-29T15:57:17.287 に答える
0

考えられるハッキング(ただし、ハッキングは悪いことですが、覚えておいてください)は、検査モジュールにアピールして、使用する関数のシグネチャを取得することです。

import inspect
#define a test function with two parameters function
def foo(a,b):
    return a+b

#obtain the list of the named arguments
acceptable = inspect.getargspec(f).args

print acceptable
#['a', 'b']

#test dictionary of kwargs
kwargs=dict(a=3,b=4,c=5)

#keep only the arguments that are both in the signature and in the dictionary
new_kwargs = {k:kwargs[k] for k in acceptable if k in kwargs}

#launch with the sanitized dictionary
f(**new_kwargs)

これは、本番コードで使用する必要のあるコードではありません。関数が一部の引数を拒否した場合は、コードを読み取り、必要なキーのみを渡す署名を取得できることを意味します。inspectを使用したハックは、安定性と読み取り性がはるかに低いため、他に方法がない場合にのみ使用してください。

于 2012-10-30T00:37:53.453 に答える
0

コードを制御できるので、** kwargsを希望どおりに渡す簡単な方法は、両方の基本クラスの__init__に**kwargsパラメーターを追加することです。

class FirstBase(object):
  def __init__(self, detail_text=desc, backed_object=backed_object,
               window=window, droppable_zone_obj=droppable_zone_obj,
               bound_zone_obj=bound_zone_object,
               on_drag_opacity=on_drag_opacity, **kwargs):
      # bla bla bla

class SecondBase(object):
      def __init__(self, size, texture, desc, backed_object, window, **kwargs):
          # bla bla bla

あなたが遭遇した失敗は、あなたの基本クラスが名前付きパラメーターしか持っていなかったためです。したがって、未知の名前を渡すと、用心棒はあなたが私のリストに載っていないと言います。基本クラスの__init__関数に**kwargsパラメーターを追加することにより、任意の名前付き値を突然渡すことができます。これは、結局のところ、** kwargsはオープンエンドのキャッチオールであり、そのどれもがないため、理解できます。名前が付けられているので、何を除外するかをどのように知るのでしょうか?それは単に、呼び出されたコードの目には名前付きの値の辞書を作成し、それらを使用するかしないかを決定します。**kwargsは完全に無視できます。

執筆の時点でディートリッヒによって現在正しいものとして受け入れられている答えは、本質的な問題を混乱させました-それはsuper()とはまったく関係がなく、**kwargsが追加されたという理由だけで彼の修正は機能します任意の名前の扉を開いた。

コードを制御できない場合は、次のことができます。

  • * argsが長すぎたり、名前が指定されていない** kwargsをアンパックしないように、引数を明示的に渡します。
  • 辞書pop関数を使用して、kwargsから無関係なパラメータをポップします。
  • または、このヘルパーメタ関数を使用できます。

    import inspect
    
    def anykwarg(function, *args, **kwargs):
        validargs = inspect.getargspec(function).args
        removals = [key for key in kwargs.keys() if key not in validargs]
        for removal in removals:
            del kwargs[removal]
        return function(*args, **kwargs)
    

このanykwargヘルパーは、kwargsパラメーターをチェックし、存在する場合は渡されたkwargsから値を削除しないように改善でき、上記で使用したinspect.getargspecはその情報を返します。これは、渡された一部のディクショナリへの参照ではなく、パラメータから生成されたローカルディクショナリであるため、anykwargのkwargsから削除しても問題ありません。

于 2015-08-21T07:55:48.370 に答える
-1

@Dietrich Eppが受け入れた回答のsuper()ように、基本クラスを呼び出す必要はありません。あなたがしているのは、残った引数を基本クラスまで渡すことだけです。これはずさんです。kwargsobject

を実行する場合super(ChildClass, self).__init__(foo, bar, **kwargs)、のスーパークラスはすべての引数、、、およびをChildClass予期する必要があります。したがって、あなたの場合、エラーが発生するということは、親クラスのメソッドにがないか、ないことを意味します。foobar**kwargsTypeError: __init__() got an unexpected keyword argument 'size'Childsize**kwargs__init__()

とのそれぞれにsuper()呼び出しが行われるFirstbaseと、コンストラクターはキーワード引数Secondbaseをアンパックしようとします。のすべてはどこかに行く必要があります。のような残り物(つまり、キーワード引数で指定されていないもの)は、残り物が入る別のものがない限り、TypeErrorを発生させます。**kwargs**kwargssize**kwargs

于 2015-11-09T22:09:59.020 に答える