从另一个模块访问对象

8 投票
2 回答
21638 浏览
提问于 2025-04-17 17:38

我是一名经验很少的程序员,正在用Python 3.3制作一个游戏,作为学习练习。目前我有一个主模块和一个战斗模块。

游戏中的人物是通过“Person”这个类的实例来表示的,这些实例是在主模块中创建的。不过,战斗模块显然需要访问这些人物对象。而且,我可能还会创建更多的模块,它们也需要访问这些对象。

我该如何让其他模块访问main.py中的Person对象呢?

现在,main.py的开头有

import combat

;但是在combat.py中添加

import main

似乎没有什么帮助。

我是否应该在一个单独的模块(比如common.py)中实例化我的对象,然后在每个需要访问它们的模块中导入这些对象呢?

2 个回答

2

如果你在 combat 模块中通过 import main 导入了主模块,那么你需要用 main.* 来访问主模块里的类和方法。

举个例子:

import main

person = main.Person()

你也可以用 from main import *import Person 来避免在前面使用 main.*

关于导入模块,有一些规则,详细内容可以参考这个链接:http://effbot.org/zone/import-confusion.htm

  1. import X 会导入模块 X,并在当前的命名空间中创建一个对这个模块的引用。换句话说,执行完这个语句后,你可以用 X.name 来引用模块 X 中定义的内容。
  2. from X import * 会导入模块 X,并在当前的命名空间中创建对该模块所有公共对象的引用(也就是所有名字不以“_”开头的东西)。换句话说,执行完这个语句后,你可以直接用简单的名字来引用模块 X 中的内容。但是 X 本身并没有被定义,所以 X.name 是不行的。如果名字已经被定义了,它会被新版本替换。如果 X 中的名字指向了其他对象,你的模块是不会察觉到的。
  3. from X import a, b, c 会导入模块 X,并在当前的命名空间中创建对指定对象的引用。换句话说,现在你可以在程序中使用 abc
  4. 最后,X = __import__(‘X’) 的效果和 import X 一样,区别在于你

    1) 以字符串的形式传递模块名,

    2) 明确地将其赋值给当前命名空间中的一个变量。

10

是的,你应该把这个问题分开处理。你现在的做法是模块之间的循环导入,这通常会引发更多问题,而不是解决问题。如果 combat 导入了 main,而 main 又导入了 combat,那么在你尝试导入时,可能会出现错误,因为 main 中的一些对象定义在那时还没有准备好。这是因为当 combat 开始执行导入时,main 还没有执行完。如果 main 是你的启动脚本,它应该只做一件事,就是通过调用另一个模块的方法来启动程序;如果所需的方法是某个类的实例方法,它也可以创建一个对象。尽量避免使用全局变量。即使现在看起来没问题,将来也可能会带来麻烦。

话说回来,你可以这样引用模块中的成员:

import common
x = common.some_method_in_common()
y = common.SomeClass()

或者

from common import SomeClass
y = SomeClass()

就我个人而言,我一般不直接引用另一个模块的方法,而是加上模块名,但这样做也是可以的:

from common import some_method_in_common
x = some_method_in_common()

我通常对类使用 from ... import ... 的方式,而对方法则通常使用第一种形式。(是的,这有时意味着我会从一个模块中单独导入特定的类,除了导入整个模块。)但这只是我个人的习惯。

还有一种语法是 强烈 不推荐 的:

from common import *
y = SomeClass()

这种方式会把 common 中所有不以下划线(_)开头的成员导入到当前的作用域中。之所以不推荐,是因为这样会让你很难辨别名字的来源,而且容易导致错误。想想这对导入:

from common import *
from some_other_module import *
y = SomeClass()

那么 SomeClass 是来自哪个模块的呢?除了去查看这两个模块,根本无法判断。更糟糕的是,如果两个模块都定义了 SomeClass,或者 SomeClass 后来被添加到 some_other_module 中,那就更麻烦了。

撰写回答