Python类装饰器扩展类导致递归
我正在覆盖Python类装饰器扩展类导致递归,python,django,forms,recursion,save,Python,Django,Forms,Recursion,Save,我正在覆盖ModelForm的save方法,不知道为什么会导致递归: @parsleyfy class AccountForm(forms.ModelForm): def save(self, *args, **kwargs): # some other code... return super(AccountForm, self).save(*args,**kwargs) 原因如下: maximum recursion depth exceeded w
ModelForm
的save方法,不知道为什么会导致递归:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountForm, self).save(*args,**kwargs)
原因如下:
maximum recursion depth exceeded while calling a Python object
Stacktrace显示该行重复调用自身:
return super(AccountForm, self).save(*args,**kwargs)
现在,欧芹装饰器是这样的:
def parsleyfy(klass):
class ParsleyClass(klass):
# some code here to add more stuff to the class
return ParsleyClass
def parsleyfy(klass):
class ParsleyClass(klass):
def save(self, *args, **kwargs):
return super(klass, self).save(*args, **kwargs)
return ParsleyClass
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
return super(forms.ModelForm, self).save(*args,**kwargs)
正如@DanielRoseman所建议的那样,欧芹装饰器扩展了AccountForm
使super(AccountForm,self)
不断地调用自己,解决方案是什么
此外,我也无法理解这会导致递归的原因。以下是我所做的工作,我可以更改parsleyfy类以覆盖save方法,如下所示:
def parsleyfy(klass):
class ParsleyClass(klass):
# some code here to add more stuff to the class
return ParsleyClass
def parsleyfy(klass):
class ParsleyClass(klass):
def save(self, *args, **kwargs):
return super(klass, self).save(*args, **kwargs)
return ParsleyClass
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
return super(forms.ModelForm, self).save(*args,**kwargs)
或者将AccountForm的保存方法更改为:
def parsleyfy(klass):
class ParsleyClass(klass):
# some code here to add more stuff to the class
return ParsleyClass
def parsleyfy(klass):
class ParsleyClass(klass):
def save(self, *args, **kwargs):
return super(klass, self).save(*args, **kwargs)
return ParsleyClass
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
return super(forms.ModelForm, self).save(*args,**kwargs)
有一件事我不知道区别是什么,那就是
super(Class,self)
vssuper(Parent,self)
我问过这个问题你可以直接调用家长的方法:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return forms.ModelForm.save(self, *args,**kwargs)
这将巧妙地避免类装饰者引入的问题。另一个选项是在不同名称的基类上手动调用decorator,而不是使用@
语法:
class AccountFormBase(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountFormBase, self).save(*args,**kwargs)
AccountForm = parsleyfy(AccountFormBase)
但是,您可能还想考虑使用A,这取决于您想做什么——这是一个通常在Django中的模型保存过程的其余部分之前应该添加的函数。
至于为什么会发生这种情况,考虑当代码被评估时会发生什么。
首先,声明一个类。我们将把这个原始类定义称为Foo
,以区别于装饰程序将创建的后期类定义。这个类有一个save
方法,可以调用super(AccountForm,self).save(…)
这个类随后被传递给decorator,decorator定义了一个新类,我们称之为Bar
,并从Foo
继承。因此,Bar.save
相当于Foo.save
——它还调用super(AccountForm,self).save(…)
。第二个类然后从装饰器返回
返回的类(Bar
)被分配给名称AccountForm
因此,当您创建一个AccountForm
对象时,您正在创建一个Bar
类型的对象。当您在其上调用.save(…)
时,它会去查找Bar.save
,它实际上是Foo.save
,因为它继承自Foo
,从未被重写
正如我们前面提到的,Foo.save
调用super(AccountForm,self).save(…)
问题在于,由于类装饰器,AccountForm
不是Foo
,而是Bar
——而Bar
的父项是Foo
所以当
Foo.save
查找AccountForm
的父项时,它会得到<代码>Foo。这意味着,当它试图调用父对象上的.save(…)
时,实际上它只会调用自身,从而导致无休止的递归。我认为您不应该返回父对象save()方法,只需执行super(AccountForm,self)。save(*args,**kwargs)您确定这是您的实际代码吗?如果您在super
调用中错误地引用了超类,通常会发生这种情况-例如,您实际上拥有AccountForm的子类,并且在被重写的save方法中,您仍在调用super(AccountForm…)
。谢谢@DanielRoseman我已经更新了question@PepperoniPizza您肯定应该返回一个modelformsuper save,因为它应该返回一个instance@JamesLinParsleyClass
做什么?您能提供一个更完整的示例吗?@JamesLink我还添加了一个注释,这是Django添加功能的首选方法,在模型保存之前立即触发。解决此问题的另一个方法是为原始类指定一个不同的名称,然后手动调用装饰器来创建您想要使用的类(例如,AccountForm
)。只要super
调用使用原始类的名称(而不是修饰版本的名称),它应该按预期工作。@JamesLin在某些情况下,直接调用父方法可能会产生其他问题,特别是那些涉及调用同一类上可能已被重写的其他方法的问题。在单继承的情况下,这些问题不会弹出,但多继承可能会出现“这不是很棘手。@杰梅斯林我用一个布尔克恩赫特建议的例子扩展了我的答案。@JamesLinsuper()的复杂性
太复杂了,无法真正放在一个注释线程中;我建议你通读一遍,如果你真的想知道更多的话。简而言之,当你使用多重继承(多个超类,例如类C(a,B):
)时,“父类”的概念变得更加复杂。