gpt4 book ai didi

Python类装饰器扩展类导致递归

转载 作者:太空狗 更新时间:2023-10-30 01:02:38 41 4
gpt4 key购买 nike

我正在覆盖 ModelForm 的保存方法,我不知道为什么会导致递归:

@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

正如@DanielRoseman 所说,扩展 AccountForm 的 Parsley 装饰器会导致 super(AccountForm,self) 继续调用自身,解决方案是什么?

我也无法理解为什么这会导致递归。

最佳答案

你可以做的就是直接调用父类的方法:

@parsleyfy
class AccountForm(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return forms.ModelForm.save(self, *args,**kwargs)

这应该巧妙地避免类装饰器引入的问题。另一种选择是在不同名称的基类上手动调用装饰器,而不是使用 @ 语法:

class AccountFormBase(forms.ModelForm):
def save(self, *args, **kwargs):
# some other code...
return super(AccountFormBase, self).save(*args,**kwargs)

AccountForm = parsleyfy(AccountFormBase)

但是,您可能还想考虑使用 pre-save signal相反,这取决于您尝试做什么 - 这是通常添加功能的方式,应该在 Django 中的模型保存过程的其余部分之前发生。


至于为什么会发生这种情况,请考虑评估代码时会发生什么。

首先,声明一个类。我们将这个原始类定义称为 Foo 以将其与装饰器将创建的后续类定义区分开来。此类有一个 save 方法,它会调用 super(AccountForm, self).save(...)

这个类然后被传递给装饰器,装饰器定义了一个我们称之为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(...) 时,它实际上只是调用自身,因此无休止的递归。

关于Python类装饰器扩展类导致递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14739809/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com