【问题标题】:How should I deal with a circular import in Google App Engine?我应该如何处理 Google App Engine 中的循环导入?
【发布时间】:2013-04-10 05:03:47
【问题描述】:

如果我有“a.py”

from google.appengine.ext import db
class A(db.Model):
    db.ReferenceProperty(b.B)
    ...other stuff

和另一个文件“b.py”

from google.appengine.ext import db
class B(db.Model):
    db.ReferenceProperty(a.A)
    ...other stuff

看起来 Python 根本不允许循环依赖。通常我猜你会改变代码,这样两个类实际上可以在不直接相互导入的情况下自行解析。也许是通过第三个中介来巩固他们对彼此的引用?但是我不能只使用普通的中间类,因为所有类最终都需要持久化到数据库中?是否有任何正确的解决方案来构建上述代码以使其正常工作?

我有一种感觉,我会得到很多“难闻的代码”、“解耦”、“糟糕的设计”等等。所以我问如果你这么说,请用一个实际的例子说明你会做什么。是否有任何解决方案需要保留引用、类和模块的原样?

谢谢。

【问题讨论】:

  • 正如你所说,糟糕的代码气味 - 除了自然的程序员懒惰之外,为什么要在公共模块之外的类之间进行循环引用?
  • 当你想要一个一对一的关系,两个持久对象可以相互引用时,你需要这个。
  • 具体来说,我有一个问题(db.Model 实体),它应该有一个或多个答案(db.Model 实体)。然而,这些答案中的每一个都可能指向另一个问题,用于进一步澄清,或者指向一个结果(db.Model 实体)。
  • +1 因为实际上在某些情况下需要这些循环引用才能获得最佳解决方案。
  • 这就像在 C 中工作,但不允许使用标题。

标签: python google-app-engine


【解决方案1】:

解决方法是在至少一个不将自身限制为特定类的模型中拥有一个 ReferenceProperty,然后强制在您自己的代码中仅引用该类。

例如,

class A(db.Model):
  b = db.ReferenceProperty()

class B(db.Model):
  a = db.ReferenceProperty(A)

您可以将任何模型实例分配给 b 变量;只要确保你只分配实际的 Bs。

【讨论】:

  • 这就是我所做的。这有点蹩脚,我的意思是我希望可能重新打开其中一个类,然后在它们都被实例化后“注入”一个引用属性,但无论如何。我想这将是正确的答案,除非我看到更好的东西。
【解决方案2】:

如果您在同一个模块中定义两个模型会发生什么?例如a_b.py

【讨论】:

  • 我确实尝试过。不过同样的事情,问题不在于它们位于不同的文件中(我相信),而是它们相互引用。
【解决方案3】:

根据documentation

ReferenceProperty 还有一个好用的 功能:反向引用。当一个模型 对另一个有 ReferenceProperty 模型中,每个被引用的实体都有一个 其值为 Query 的属性 返回的所有实体 第一个引用它的模型。

所以你应该可以使用自动添加的反向引用。

【讨论】:

  • 这正是您所需要的。
  • 不幸的是,我试图将 A 和 B 保持在一种树结构中,因此事物可以从根到叶的方向相互引用,但不能从叶到根的方向。您让“叶子”引用“根”然后使用自动生成的从“根”到“叶子”的反向引用的解决方案可能会解决循环依赖,但会缠绕树。
  • 反向引用与反向引用不同。
【解决方案4】:

从技术上讲,您可以将循环依赖替换为交集表。

就我而言,我有非规范化模型,PlayerMatch

Matches 和 Players 之间的关系是多对多的,(一个 Player 玩过一场或多场比赛,而 Match 引用一个或多个球员)。

我需要什么:

class Match(db.Model):
    p1 = db.ReferenceProperty( Player )
    p2 = db.ReferenceProperty( Player )

class Player(db.Model):
    # Remember what match player is currently in, for victor reporting
    currentMatch = db.ReferenceProperty( Match )

选项 0:Wooble 建议的内容

选项 1:对其进行规范化(使用交集表)

class Match(db.Model):
    # ...

class Player(db.Model):
    # ...

# Every match has multiple entries here (as many 1 for
# each player-in-match entry).  This will make retrieval
# slower, but more-correct (it is "normalized" now)
class PlayersInMatches(db.Model):
    player=db.ReferenceProperty(Player)
    match=db.ReferenceProperty(Match)
    isCurrent=db.BooleanProperty()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-10
    • 2015-04-25
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2015-10-29
    • 2012-04-02
    • 1970-01-01
    相关资源
    最近更新 更多