【问题标题】:Python access parent object instancesPython 访问父对象实例
【发布时间】:2010-07-26 13:30:34
【问题描述】:

我目前正在尝试使用 PyGame 编写多文件 Python (2.6.5) 游戏。问题是其中一个文件“pyconsole.py”需要能够调用由主文件“main.py”导入的其他对象的实例上的方法。问题是我在主文件中有一个列表来保存所有游戏对象(玩家的船、敌船、车站等)的实例,但我似乎无法从该列表中调用方法“pyconsole.py”尽管我在主循环开始之前在“main.py”中执行了from pyconsole import *。这根本不可能吗,我是否应该使用 M4 将每个文件组合成一个单独的文件,然后进行字节码编译和测试/分发?

例子:

bash$ cat test.py
#!/usr/bin/python

import math, distancefrom00
foo = 5

class BarClass:
    def __init__(self):
        self.baz = 10
    def get(self):
        print "The BAZ is ", self.baz
    def switch(self)
        self.baz = 15
        self.get()

bar = BarClass()

def main():
    bar.switch()
    print distancefrom00.calculate([2, 4])

if __name__ == '__main__': main()

bash$ cat distancefrom00.py
#!/usr/bin/python

import math
import test

def calculate(otherpoint):
    return str(math.hypot(otherpoint[0], otherpoint[1]))+" (foo = "+str(test.foo)+"; "+test.bar.get()+")"

bash$ python test.py
The BAZ is  15
The BAZ is  10
Traceback (most recent call last):
  File "test.py", line 24, in <module>
    if __name__ == '__main__': main()
  File "test.py", line 22, in main
    print distancefrom00.calculate([2, 4])
  File "/home/archie/Development/Python/Import Test/distancefrom00.py", line 8, in calculate
    return str(math.hypot(otherpoint[0], otherpoint[1]))+" (foo = "+str(test.foo)+"; "+test.bar.get()+")"
TypeError: cannot concatenate 'str' and 'NoneType' objects

如果我对 Python 名称、类和所有这些东西的理解有限,那么 NoneType 意味着名称 test.bar.get() - 因此,test.bar - 没有分配给任何东西。

【问题讨论】:

  • “我似乎无法调用方法”是什么意思?请包含一些示例代码并提供您得到的异常。
  • 啊 - 以防万一。为了您自己的安全,请不要在任何构建脚本中涉及 M4。 Python 模块可以正常工作,但您在某处遇到了错误。 M4 是邪恶的。
  • 只是出于好奇,M4 怎么样(除了忘记使用-P 标志以免破坏现有文本)是邪恶的?

标签: python pygame python-import


【解决方案1】:

问题是其中一个文件, “pyconsole.py”,需要能够 在其他实例上调用方法 由主文件导入的对象, “main.py”。

这听起来像是依赖关系是错误的。一般来说,什么都不应该调用“向后”到主文件。那个 main.py 应该是把所有其他东西结合在一起的粘合剂,任何东西都不应该依赖它。从技术上讲,依赖关系应该形成directed acyclic graph。一旦你在依赖图中找到一个循环,就将共同的方面移到一个新文件中以打破循环。

因此,将“pyconsole.py”使用的“main.py”中的内容移到一个新文件中。然后让 'main.py' 和 'pyconsole.py' 导入该新文件。

【讨论】:

  • 好的,如果我的理解正确,这意味着资源的每个实例(声音/精灵对象、游戏对象列表等)都需要放在一个单独的文件中,然后由main.pypyconsole.py 以及处理这些对象的所有其他内容导入?我的问题是:这样做实际上会导致每个单独的文件都在使用 imported 的每个其他文件的命名空间的相同“副本”,或者我最终会为每个命名空间制作无休止的副本,每个一个只受另一个文件的影响(显然,这不是选择的行为)?
  • 这不是关于资源实例,而是关于代码依赖性。资源可以在任何你喜欢的地方实例化。但是,如果您有一个对象存在于一个文件中并在许多其他文件中使用,那听起来像是一个全局变量,几乎总是一个坏主意。至于您的命名空间问题,在一个程序中,每个模块(即您导入的文件)仅存在一次。如果两个不同的文件访问 pyconsole.something,那么在这两种情况下,该名称都指的是同一个对象。
  • 啊,那是我不明白的。我不确定 Python 是否在内部使用了类似于保护 C[++] 头文件不被 #include -ed 使用常量多次的方案。感谢您澄清这一点。
  • 为了迂腐,在 C++ 中它们实际上并不是常量,只是预处理器定义。 Python 会自动执行类似的检查,是的。
【解决方案2】:

除了其他答案,请注意,当您将 test.py 作为脚本运行时,它是模块 __main__。当您从 distancefrom00.py 导入 test.py 时,会创建一个新的 test 模块。主脚本中的bar 和可从distancefrom00.py 访问的test.bar 完全不相关。它们甚至不是同一个类:一个是 __main__.BarClass 而另一个是 test.BarClass 实例。

这就是为什么你得到两个输出 15 和 10:主脚本 bar 已经调用了它的 switch 方法,但是测试模块 bar 没有被切换。

抛开循环导入不谈,将主脚本导入另一个模块也有其自身的缺陷。

【讨论】:

    【解决方案3】:

    您是否在main.py 中实例化pyconsole 中的对象?如果您在pyconsole 中有一个名为PyConsole 的类,请为其__init__ 方法提供一个获取游戏对象列表的参数。这样你的pyConsole 对象就会引用这些对象。

    希望这会有所帮助。看来您只是误解了 Python 处理导入模块的方式。

    【讨论】:

      【解决方案4】:

      提交代码的问题是BarClass类的get方法返回值None,因为方法体只包含一个打印语句。因此,在distancefrom00.py 中,函数calculate 的结果是:

      str + str + str + str + None + str
      

      因此,TypeError: cannot concatenate a 'str' and 'NoneType' objects

      您可以通过从对get 的调用中返回一个字符串来解决此问题。例如,

      def get(self):
          return "The BAZ is %s" % self.baz
      

      另外,请注意,您的两个文件中有一个循环导入。 test.py 导入 distancefrom00.pydistancefrom00.py 导入 test.py。正如 Kylotan 所说,循环依赖是不好的

      【讨论】:

        猜你喜欢
        • 2018-02-18
        • 1970-01-01
        • 1970-01-01
        • 2018-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-14
        • 2021-03-01
        相关资源
        最近更新 更多