django 相互引用的python类

avwztpqn  于 2022-12-14  发布在  Go
关注(0)|答案(8)|浏览(129)

我有两个互相引用的类,但显然编译器会抱怨。有什么办法可以解决这个问题吗?

编辑

实际上,我的代码与Hank Gay使用的代码略有不同。因此,python肯定可以处理某些类型的循环引用,但它在以下情况下抛出错误。下面是我得到的代码,我得到了一个“name Y not defined error”

class X(models.Model):

        creator = Registry()
        creator.register(Y)

class Y(models.Model):
    a = models.ForeignKey(X)
    b = models.CharField(max_length=200)

希望这有助于澄清。有什么建议吗。

to94eoyn

to94eoyn1#

在Python中,类中的代码在类被加载时运行。
这到底是什么意思?- )
请考虑以下代码:

class x:
    print "hello"
    def __init__(self): print "hello again"

当你加载包含代码的模块时,python会打印hello,无论何时创建一个x,python都会打印hello again
你可以认为def __init__(self): ...等同于__init__ = lambda self: ...,除了没有python lambda限制外,也就是说,def是一个赋值,这也许可以解释为什么运行方法外的代码而不是方法内的代码。
当你的代码说

class X(models.Model):
    creator = Registry()
    creator.register(Y)

Y有值之前,当模块加载时引用Y,可以将class X视为赋值(但是我不记得创建匿名类的语法了;可能是对type的调用)
您可能需要执行以下操作:

class X(models.Model):
    pass
class Y(models.Model):
    foo = something_that_uses_(X)
X.bar = something_which_uses(Y)

即创建Y后,再创建X的类属性引用Y,反之亦然:首先创建Y,然后创建X,如果更容易,再创建依赖于XY的属性。
希望这有帮助:)

xtfmy6hx

xtfmy6hx2#

错误是在类X的(可执行)定义期间尝试执行creator.register(Y),并且在该阶段,类Y没有定义。classdef是执行的语句(通常在导入时执行);它们不是“声明”。
建议:告诉我们你正在努力实现什么--也许可以作为一个新问题。

6ju8rftf

6ju8rftf3#

更新:他在我回答后改变了问题。根据新的问题,目前接受的解决方案更好。
你说问题出在哪?

class A(object):
    def __init__(self):
        super(A, self).__init__()

    def b(self):
        return B()

class B(object):
    def __init__(self):
        super(B, self).__init__()

    def a(self):
        return A()

这编译和运行得很好。

rvpgvaaj

rvpgvaaj4#

只要您在方法中工作,就可以访问类对象。
因此,如果将creator.register(Y)移到__init__内部,上面的示例不会出现问题。但是,不能循环引用方法外部的类。

ybzsozfc

ybzsozfc5#

这是一个很棒的问题,虽然其他人已经回答了,但我将随时提供另一个例子。
考虑一下这个程序。

@dataclass
class A:
    b: B

class B:
    def __init__(self):
        pass

b现在是级变量,此程序无法运行。在Python解释器加载时,名称B未定义(执行)A类的代码。与编译语言不同(例如C/C++),解释器逐个命令地从文件的开头到结尾执行代码,因为Python在定义类A时需要知道B是什么,所以它失败了。B只是后来才定义的。
现在,考虑一个稍微不同的程序。

class A:
    def __init__(self):
        self.b = B()

class B:
    def __init__(self):
        pass

b现在是一个object级别的变量,这个程序可以工作,Python仍然在一次遍历中从文件的开头到结尾执行代码,但是,现在,在读取X1 M8 N1 X行时,它不需要知道X1 M7 N1 X是什么。这是因为__init__方法只在某人想要构造A类的对象时才执行。(如果已经定义了B),则__init__在需要时可以正常工作。

epfja78i

epfja78i6#

我来晚了,但我想展示一下我是如何解决这个问题的。
您可以将一个类嵌套到另一个类中,并且这两个类将能够相互引用
这里示范一下:

class X():

    class Y():
        def x(self):
            return X()

    def y(self):
        return self.Y()

a1 = X()
a2 = a1.y()

b1 = X.Y()
b2 = b1.x()

您还可以创建一个包含要引用的类的BaseClass

class Z():

    class X():
        def y(self):
            return Z.Y()

    class Y():
        def x(self):
            return Z.X()
v8wbuo2f

v8wbuo2f7#

众所周知,我们试图从物理世界中的一个诞生点来想象两个独立但又相互依赖的实体,这看起来是一个不言而喻的矛盾。但是,当涉及到软件领域时,我们经常遇到这种所谓的“循环引用或相互引用”的问题。这在面向对象设计中可能会更加严重。其中,通常以模仿物理元件的方式定义互操作软件元件并使其彼此相关,但仍作为纯逻辑存在。
在许多编程语言中,这些问题已经通过在函数或类的to-reference元素之前声明to-be-reference元素来解决,只是以签名的形式(没有主体定义),然而,这种规避技巧对于基于脚本的语言(如Python)似乎不再可用,也不再有用。
在Python中,我们最好从软件工程的Angular 来处理“循环引用”,如下所示:
1.如果可能的话,最好重新设计类而不是循环的;有几种方法(例如,类的去或组合、回调函数、观察者或订户模式等)来使得元素之间的引用出现在同一类内、被移除或被反转。
1.在线性化元素之间的一些循环链可能会导致质量或生产率等方面出现更严重的问题的情况下,我们可以采取另一种措施将其传统的构建阶段分为两个阶段:创造和构造。例如,朋友中的两个人注定在观察到对方的出生后绝对出生,他们可以这样做,即他们是第一个出生的,然后在任何有意义的和可观察的事件发生之前建立他们的友谊。注意,如果我们在处理内部聚合对象时面临某种极端复杂性或需要某种高度的完整性,应用工厂模式将得到回报。

nqwrtyyt

nqwrtyyt8#

这个问题很可能不是Python的问题。我认为是SQL的问题。类通过抽象层转换成SQL查询来创建一个表。你试图从一个表引用另一个当时还不存在的表。
在SQL中,您可以通过以下方法解决这个问题:首先创建不带引用的表,然后修改它们以进行引用,
然而我不确定我的答案,所以请多加考虑,如果Django的数据库抽象层不能很好地处理交叉引用,我会感到非常惊讶。

相关问题