如何使用类似的 Django 模型方法避免代码重复?
How to avoid code duplication with similar Django model methods?
以下模型包含两个几乎相同的函数list_ancestors
和list_descendants
。什么是只编写一次此代码的好方法?
class Node(models.Model):
name = models.CharField(max_length=120, blank=True, null=True)
parents = models.ManyToManyField('self', blank=True, symmetrical=False)
def list_parents(self):
return self.parents.all()
def list_children(self):
return Node.objects.filter(parents=self.id)
def list_ancestors(self):
parents = self.list_parents()
ancestors = set(parents)
for p in parents:
ancestors |= set(p.list_ancestors()) # set union
return list(ancestors)
def list_descendants(self):
children = self.list_children()
descendants = set(children)
for c in children:
descendants |= set(c.list_descendants()) # set union
return list(descendants)
def __str__(self):
return self.name
编辑:从以下答案得出的解决方案:
def list_withindirect(self, arg):
direct = getattr(self, arg)()
withindirect = set(direct)
for d in direct:
withindirect |= set(d.list_withindirect(arg))
return list(withindirect)
def list_ancestors(self):
return self.list_withindirect('list_parents')
def list_descendants(self):
return self.list_withindirect('list_children')
使用字符串并在对象上调用 getattr 以获取可调用函数。
def list_withindirect(self, fn1):
direct = getattr(self, fn1)()
withindirect = set(direct)
for d in direct:
withindirect |= set(d.list_withindirect(fn1))
return list(withindirect)
def list_ancestors(self):
return self.list_withindirect('list_parents')
这看起来像是 bound 和 unbound 方法问题中的问题。
当您最初将 self.list_parents
传递给 self.list_withindirect(list_direct)
时,一切正常。
但是当你递归传递相同的! self.list_parents
到 d.list_withindirect
(即后代),你不小心用最顶层调用者对象的父代填充了你的 direct
变量,而不是 d
.
例如,它可以使用getattr
来解决,就像2ps 回答的那样(更新:他的原始代码中的错误是在那里的评论中找到).
以下模型包含两个几乎相同的函数list_ancestors
和list_descendants
。什么是只编写一次此代码的好方法?
class Node(models.Model):
name = models.CharField(max_length=120, blank=True, null=True)
parents = models.ManyToManyField('self', blank=True, symmetrical=False)
def list_parents(self):
return self.parents.all()
def list_children(self):
return Node.objects.filter(parents=self.id)
def list_ancestors(self):
parents = self.list_parents()
ancestors = set(parents)
for p in parents:
ancestors |= set(p.list_ancestors()) # set union
return list(ancestors)
def list_descendants(self):
children = self.list_children()
descendants = set(children)
for c in children:
descendants |= set(c.list_descendants()) # set union
return list(descendants)
def __str__(self):
return self.name
编辑:从以下答案得出的解决方案:
def list_withindirect(self, arg):
direct = getattr(self, arg)()
withindirect = set(direct)
for d in direct:
withindirect |= set(d.list_withindirect(arg))
return list(withindirect)
def list_ancestors(self):
return self.list_withindirect('list_parents')
def list_descendants(self):
return self.list_withindirect('list_children')
使用字符串并在对象上调用 getattr 以获取可调用函数。
def list_withindirect(self, fn1):
direct = getattr(self, fn1)()
withindirect = set(direct)
for d in direct:
withindirect |= set(d.list_withindirect(fn1))
return list(withindirect)
def list_ancestors(self):
return self.list_withindirect('list_parents')
这看起来像是 bound 和 unbound 方法问题中的问题。
当您最初将 self.list_parents
传递给 self.list_withindirect(list_direct)
时,一切正常。
但是当你递归传递相同的! self.list_parents
到 d.list_withindirect
(即后代),你不小心用最顶层调用者对象的父代填充了你的 direct
变量,而不是 d
.
例如,它可以使用getattr
来解决,就像2ps 回答的那样(更新:他的原始代码中的错误是在那里的评论中找到).