[英]Python class decorator extending class causes recursion
I'm overwriting the save method of a ModelForm
and I don't know why it would cause recursion: 我正在覆盖ModelForm
的save方法,我不知道它为什么会导致递归:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountForm, self).save(*args,**kwargs)
Causes this: 导致这个:
maximum recursion depth exceeded while calling a Python object
Stacktrace shows this line repetitively calling itself: Stacktrace显示此行反复调用自身:
return super(AccountForm, self).save(*args,**kwargs)
Now, the parsley decorator is like this: 现在,欧芹装饰器是这样的:
def parsleyfy(klass):
class ParsleyClass(klass):
# some code here to add more stuff to the class
return ParsleyClass
As @DanielRoseman suggested that the Parsley decorator extending the AccountForm
causes the super(AccountForm,self)
to keep calling itself, what's the solution? 正如@DanielRoseman所说,扩展AccountForm
的Parsley装饰器导致super(AccountForm,self)
继续调用自己,解决方案是什么?
Also I cannot get my head around this why this would cause recursion. 此外,我无法理解为什么这会导致递归。
What you could do is just call the parent's method directly: 你能做的就是直接调用父方法:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return forms.ModelForm.save(self, *args,**kwargs)
This should neatly avoid the issue introduced by your class decorator. 这应该整齐地避免您的类装饰器引入的问题。 Another option would be to manually call the decorator on a differently named base class, rather than using @
syntax: 另一种选择是在不同名称的基类上手动调用装饰器,而不是使用@
语法:
class AccountFormBase(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountFormBase, self).save(*args,**kwargs)
AccountForm = parsleyfy(AccountFormBase)
However, you might also want to consider using a pre-save signal instead, depending on what you're trying to do - it's how one normally adds functionality that should happen before the rest of the model save process in Django. 但是,您可能还需要考虑使用预保存信号 ,具体取决于您尝试执行的操作 - 这是通常添加在Django中的其余模型保存过程之前应该发生的功能的方式。
As for why this is occurring, consider what happens when the code is evaluated. 至于为什么会发生这种情况,请考虑在评估代码时会发生什么。
First, a class is declared. 首先,声明一个类。 We'll refer to this original class definition as Foo
to distinguish it from the later class definition that the decorator will create. 我们将这个原始的类定义称为Foo
以区别于装饰器将创建的后一个类定义。 This class has a save
method which makes a super(AccountForm, self).save(...)
call. 这个类有一个save
方法,它可以调用super(AccountForm, self).save(...)
。
This class is then passed to the decorator, which defines a new class which we'll call Bar
, and inherits from Foo
. 然后将该类传递给装饰器,装饰器定义一个我们称之为Bar
的新类,并继承自Foo
。 Thus, Bar.save
is equivalent to Foo.save
- it also calls super(AccountForm, self).save(...)
. 因此, Bar.save
相当于Foo.save
- 它也称为super(AccountForm, self).save(...)
。 This second class is then returned from the decorator. 然后从装饰器返回第二个类。
The returned class ( Bar
) is assigned to the name AccountForm
. 返回的类( Bar
)被分配给名称AccountForm
。
So when you create an AccountForm
object, you're creating an object of type Bar
. 因此,当您创建AccountForm
对象时,您将创建一个Bar
类型的对象。 When you call .save(...)
on it, it goes and looks up Bar.save
, which is actually Foo.save
because it inherited from Foo
and was never overridden. 当你在它上面调用.save(...)
时,它会查找Bar.save
,它实际上是Foo.save
因为它继承自Foo
并且从未被覆盖过。
As we noted before, Foo.save
calls super(AccountForm, self).save(...)
. 正如我们之前提到的, Foo.save
调用super(AccountForm, self).save(...)
。 The problem is that because of the class decorator, AccountForm
isn't Foo
, it's Bar
- and Bar
's parent is Foo
. 问题是因为类装饰器, AccountForm
不是Foo
,它是Bar
- 而Bar
的父级是Foo
。
So when Foo.save
looks up AccountForm
's parent, it gets... Foo
. 所以当Foo.save
查找AccountForm
的父级时,它会得到...... Foo
。 This means that when it tries to call .save(...)
on that parent, it actually just winds up calling itself, hence the endless recursion. 这意味着当它试图在该父节点上调用.save(...)
时,它实际上只是调高自身,因此无休止的递归。
Here is what I have done to make it work, I could either change parsleyfy class to overwrite the save method like this: 以下是我为使其工作所做的工作,我可以更改parsleyfy类来覆盖save方法,如下所示:
def parsleyfy(klass):
class ParsleyClass(klass):
def save(self, *args, **kwargs):
return super(klass, self).save(*args, **kwargs)
return ParsleyClass
or change the AccountForm's save method to be like this: 或者将AccountForm的save方法更改为:
@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
return super(forms.ModelForm, self).save(*args,**kwargs)
One thing I don't what the difference is, is super(Class, self)
vs super(Parent, self)
I have asked this question 有一件事,我没有什么区别,是super(Class, self)
与super(Parent, self)
我问过这个问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.