python 相互引用的python类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1046150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
python classes that refer to each other
提问by Daniel
I have two classes that refer to each other, but obviously the compiler complains. Is there any way around this?
我有两个相互引用的类,但显然编译器会抱怨。有没有办法解决?
EDIT
编辑
Actually my code is slightly different than what Hank Gay uses. So python can definitely deal with some kinds of circular references, but it tosses an error in the following situation. Below is what I've got and I get an 'name Y not defined error'
实际上,我的代码与 Hank Gay 使用的代码略有不同。所以python肯定可以处理一些循环引用,但是在下面的情况下会报错。下面是我得到的,我得到一个“名称 Y 未定义错误”
class X(models.Model):
creator = Registry()
creator.register(Y)
class Y(models.Model):
a = models.ForeignKey(X)
b = models.CharField(max_length=200)
Hope this helps clarify. Any suggestions.
希望这有助于澄清。有什么建议。
回答by Jonas K?lker
In python, the code in a class is run when the class is loaded.
在python中,类中的代码在类加载时运行。
Now, what the hell does that mean? ;-)
现在,这到底是什么意思?;-)
Consider the following code:
考虑以下代码:
class x:
print "hello"
def __init__(self): print "hello again"
When you load the module that contains the code, python will print hello
. Whenever you create an x
, python will print hello again
.
当您加载包含代码的模块时,python 将打印hello
. 无论何时创建x
,python 都会打印hello again
.
You can think of def __init__(self): ...
as equivalent with __init__ = lambda self: ...
, except none of the python lambda restrictions apply. That is, def
is an assignment, which might explain why code outside methods but not inside methods is run.
您可以认为def __init__(self): ...
与 等效__init__ = lambda self: ...
,除了没有任何 python lambda 限制适用。也就是说,def
是一个赋值,它可以解释为什么运行方法之外的代码而不是方法内部的代码。
When your code says
当你的代码说
class X(models.Model):
creator = Registry()
creator.register(Y)
You refer to Y
when the module is loaded, before Y
has a value. You can think of class X
as an assignment (but I can't remember the syntax for creating anonymous classes off-hand; maybe it's an invocation of type
?)
你指的是Y
当模块加载时,之前Y
有一个值。您可以将其class X
视为一项作业(但我不记得用于立即创建匿名类的语法;也许它是对type
?的调用?)
What you may want to do is this:
您可能想要做的是:
class X(models.Model):
pass
class Y(models.Model):
foo = something_that_uses_(X)
X.bar = something_which_uses(Y)
That is, create the class attributes of X
which reference Y
after Y
is created. Or vice versa: create Y
first, then X
, then the attributes of Y
which depend on X
, if that's easier.
即创建X
引用Y
后的类属性Y
。反之亦然:Y
先创建,然后创建,然后创建依赖于X
的属性,如果这样更容易的话。Y
X
Hope this helps :)
希望这可以帮助 :)
回答by Hank Gay
UPDATE: He changed the question after my answer. The currently accepted solution is better in light of the new question.
更新:他在我回答后改变了问题。鉴于新问题,当前接受的解决方案更好。
What are you saying is the problem?
你说是什么问题?
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()
This compiles and runs just fine.
这编译并运行得很好。
回答by Daniel
As long as you are working within a method you can access the class object.
只要您在方法中工作,您就可以访问类对象。
Thus the example above has no problems if creator.register(Y)
is moved inside __init__
. However, you cannot have circular references to classes outside of methods.
因此上面的例子如果creator.register(Y)
被移动到里面就没有问题__init__
。但是,您不能对方法之外的类进行循环引用。
回答by John Machin
The error is that execution of creator.register(Y)
is attempted during the (executable) definition of class X, and at that stage, class Y is not defined. Understand this: class
and def
are statements that are executed (typically at import time); they are not "declarations".
错误是creator.register(Y)
在类 X 的(可执行)定义期间尝试执行,并且在该阶段未定义类 Y。理解这一点:class
和def
是执行的语句(通常在导入时);它们不是“声明”。
Suggestion: tell us what you are trying to achieve -- perhaps as a new question.
建议:告诉我们您想要达到的目标——也许作为一个新问题。
回答by Joon-Sang Lee
As we well know, it looks like a self-evident contradiction that we try to imagine of two independent but inter-dependent entities just from a point of their birth in physical world. But, when it comes to the area of software, we often encounter this kind of issues so called 'circular or mutual references'. That may come more seriously in object-oriented design, in which inter-operating software elements are usually defined and related to one another in imitation of such a way as physical ones, but still as pure logical existences.
众所周知,我们试图从两个独立但相互依存的实体在物理世界中的出生点来想象它们,这看起来是一个不言而喻的矛盾。但是,当涉及到软件领域时,我们经常会遇到这种所谓的“循环或相互引用”的问题。这在面向对象的设计中可能会更严重,其中互操作的软件元素通常被定义并相互关联,以模仿物理元素的方式,但仍然是纯粹的逻辑存在。
In many programming languages, these issues have been resolved by declaring to-be-referenced elements in time before their to-reference elements just in form of signatures (no body definitions) for functions or classes. However, that sort of evading tricks seems neither longer available nor useful for a script-based language like Python.
在许多编程语言中,这些问题已通过仅以函数或类的签名(没有主体定义)的形式在它们的被引用元素之前及时声明被引用元素来解决。然而,这种规避技巧对于像 Python 这样的基于脚本的语言来说似乎不再可用,也不再有用。
In Python, we'd better approach 'circular reference' in a view of software engineering, as follows:
在Python中,从软件工程的角度来看,我们最好采用“循环引用”的方式,如下:
It's much better to redesign classes not circular if possible; there are several ways (e.g. class de- or composition, call-back function, observer or subscriber patterns, and etc.) to make references between elements occur within the same class, removed or inverse.
In cases that linearizing some circular chains between elements might cause more serious problem in some aspect like quality or productivity, we can take another measure to separate their traditional construction phase into two: creating and structuring. For example, two persons in friends who are destined to have their birth absolutely after observing the other's birth can do in a way that they are first born and then have their friendship just before any meaningful and observable occasions happen. Note that if we face some extreme complexity or need some high degree of integrity in dealing with inter-aggregated objects, applying a Factory pattern will pay off.
如果可能,最好重新设计非循环类;有几种方法(例如类分解或组合、回调函数、观察者或订阅者模式等)使元素之间的引用发生在同一类中、删除或反向。
如果在元素之间线性化一些循环链可能会在质量或生产力等方面造成更严重的问题,我们可以采取另一种措施将其传统的构建阶段分为两个:创建和结构化。例如,朋友中的两个人在观察到对方的出生后绝对注定要出生,他们可以在任何有意义和可观察的场合发生之前以一种他们先出生的方式建立他们的友谊。请注意,如果我们在处理相互聚合的对象时面临一些极端的复杂性或需要高度的完整性,则应用工厂模式将获得回报。
回答by Martin P. Hellwig
The problem is most likely not Python. I would think it is an SQL issue. The classes are via an abstraction layer converted to an SQL query to create a table. You are trying to reference from one table another one that at the time does not exist yet.
问题很可能不是 Python。我认为这是一个 SQL 问题。这些类通过抽象层转换为 SQL 查询来创建表。您正试图从一张表中引用当时尚不存在的另一张表。
In SQL you would solve this by creating the table first without the references and after that modify them to make those references,
在 SQL 中,您可以通过首先创建没有引用的表,然后修改它们以创建这些引用来解决这个问题,
However I am not sure about my answer, so take it with lots of seasoning, I would be actually quite surprised if Django's database abstraction layer doesn't deal with cross references nicely.
但是,我不确定我的答案,因此请多加调味,如果 Django 的数据库抽象层不能很好地处理交叉引用,我实际上会感到非常惊讶。