2011-08-15 5 views
1

私はなぜ明示的に署名引数を指定しても動作しませんが、盲目的に* argsをやっていることを理解しようとしている、** kwargs作品!私は本当に2つの違いがあまり見えませんか?動作しません署名の明示的な引数は機能しませんか?非常に奇妙な

例:

from django.db.models import CharField as _CharField 

class CharField(_CharField): 
    def get_db_prep_value(self, value, connection, prepared=False): 
     if self.blank == self.null == self.unique == True and value == '': 
      value = None 

     return super(CharField, self).get_db_prep_value(value, connection, prepared) # <--- this does not work! 

をし、私次のエラーを取得:これはうまく動作しますが

File "/home/googledroid/Workspace/eclipse/gameproject/virtualenv/lib/python2.6/site-packages/django/db/models/fields/__init__.py", line 276, in get_db_prep_save 
    return self.get_db_prep_value(value, connection=connection, prepared=False) 
    File "/home/googledroid/Workspace/eclipse/gameproject/virtualenv/lib/python2.6/site-packages/django/db/models/fields/subclassing.py", line 53, in inner 
    return func(*args, **kwargs) 
    File "/home/googledroid/Workspace/eclipse/gameproject/src/fields/__init__.py", line 13, in get_db_prep_value 
    return super(CharField, self).get_db_prep_value(value, connection, prepared) 
    File "/home/googledroid/Workspace/eclipse/gameproject/virtualenv/lib/python2.6/site-packages/django/db/models/fields/subclassing.py", line 53, in inner 
    return func(*args, **kwargs) 
    File "/home/googledroid/Workspace/eclipse/gameproject/virtualenv/lib/python2.6/site-packages/django/db/models/fields/subclassing.py", line 53, in inner 
    return func(*args, **kwargs) 
TypeError: get_db_prep_value() got multiple values for keyword argument 'connection' 

を:Djangoのソース、django.db.models.subclassing.call_with_connection_and_prepared.inner()

from django.db.models import CharField as _CharField 

class CharField(_CharField): 
    def get_db_prep_value(self, value, *args, **kwargs): 
     if self.blank == self.null == self.unique == True and value == '': 
      value = None 

     return super(CharField, self).get_db_prep_value(value, *args, **kwargs) 

、私はkwargsのいくつかの削除がありますが、完全にはわからないのはなぜですか?

答えて

3

事実、connection引数は、常にキーワード引数として渡されるはずです。 django.db.models.fields.subclassingのコードは、それがkwargs辞書に存在するかどうかのみをチェックし、そうでなければDeprecationWarningを発行してそこに追加します。位置指定引数はチェックされていないので、渡された位置引数の両方が転送されますが、関数ラッパーによってデフォルトで指定されたキーワード引数も渡されます。したがって、紛争。

あなたのコードを動作させるために、あなたがする必要があるすべては、このさ:ちょうどFYI、開発版ではすべてのそれらのラッパーは、あなたの現在のコードは、おそらくトランクに対して機能するであろうことを意味する、削除されました

 return super(CharField, self).get_db_prep_value(value, connection=connection, prepared=prepared) 

。しかし、引数をkwargsに保つことが最善と考えられます。

+0

これは意味があります。ありがとうございました!私が100%であることを確認するために、オリジナルのField.get_db_prep_value()メソッドを呼び出す前に、サブクラスでこれを行います。そのため、Field.get_db_prep_value()メソッドは影響を受けません(ただし、継承チェーンの最上位にあります)。 – GoogleDroid

+0

事は、Django 1.3でです。Xでは、すべてのフィールドクラスはメタクラス「LegacyConnection」を使用します。このメタクラスは、 'db_type'、' get_db_prep_save'、 'get_db_prep_lookup'、' get_db_prep_value'のメソッドを、以下を行うラッパーで置き換えます:1)ラップされたメソッドが 'connection'を引数として受け入れることを確認し、2) '接続' ** kwarg **が提供されていることを確認してください。内部的には、ORM内のすべてのDjango機構がkwargsを使用しており、サブクラス化するときにもそれらを使用することが期待されます。 – koniiiik

+0

私は完全にdjangoの内部についてはそれほど明確ではないし、おそらくそれの要点を持っているが、ありがとう! :D – GoogleDroid

0

私は、Djangoのソースが入手できていないので、これは単なる推測です:何Fooに渡されることはBarBazにコール署名に応じて異なること

お知らせ:

class Foo(object): 
    def get_db_prep_value(self,*args,**kwargs): 
     print(args,kwargs) 

class Bar(Foo): 
    def get_db_prep_value(self,value,connection,prepared=False): 
     super(Bar,self).get_db_prep_value(value,connection,prepared) 

class Baz(Foo): 
    def get_db_prep_value(self,*args,**kwargs):   
     super(Baz,self).get_db_prep_value(*args,**kwargs) 

bar=Bar() 
bar.get_db_prep_value(1,2,prepared=True) 
# ((1, 2, True), {}) 

baz=Baz() 
baz.get_db_prep_value(1,2,prepared=True) 
# ((1, 2), {'prepared': True}) 

使用

super(Bar,self).get_db_prep_value(value,connection,prepared) 

preparedは、位置引数に渡されますリストargs

しかし、あなたは

super(Baz,self).get_db_prep_value(*args,**kwargs) 

preparedを使用する場合、キーワード辞書kwargsに渡されます。

+0

ありがとうございます。 – GoogleDroid

0

"double splat"構文を使用して定義された関数の場合、呼び出し元は呼び出し側がキーワード引数ごとに明示的に辞書キーを渡す必要があります。私はget_db_prep_valueが以下の関数の最初のように定義されていると確信しています。

def usessplat(**kwargs): 
    print 'connection = ' + kwargs.get('connection', 'None') 

def nosplat(connection=None) 
    print 'connection = ' + str(connection) 

usessplat('foo') # raises TypeError 
nosplat('foo') # no exception 
関連する問題