我试图理解为什么明确指定签名参数不起作用,但只是盲目地做一个* args,** kwargs有效!我真的看不出两者之间有多大区别?
不起作用的示例:
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'
虽然这很好用:
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)
在django来源django.db.models.subclassing.call_with_connection_and_prepared.inner()
,我看到有一些kwargs的删除,但不完全确定为什么?
答案 0 :(得分:3)
问题是,connection
参数应该始终作为关键字参数传递。 django.db.models.fields.subclassing
中的代码仅检查它是否存在于kwargs
字典中,如果不存在,则会发出DeprecationWarning
并将其添加到其中。不检查位置参数,所以最后发生的是你传递的位置参数都被转发,但函数包装器默认提供的关键字参数也会被传入。因此,冲突。
要使代码正常工作,您需要做的就是:
return super(CharField, self).get_db_prep_value(value, connection=connection, prepared=prepared)
仅供参考,在开发版本中,所有这些包装器都已被删除,这意味着您当前的代码可能会对主干进行操作。但是,最好将参数保留在kwargs
。
答案 1 :(得分:0)
我没有django来源,所以这只是猜测:
请注意,传递给Foo
的内容会有所不同,具体取决于Bar
和Baz
中的来电签名:
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
会传递到关键字dict kwargs
。
答案 2 :(得分: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