【问题标题】:How can I have a variable be changed throughout multiple Python modules?如何在多个 Python 模块中更改变量?
【发布时间】:2014-08-18 03:26:28
【问题描述】:

我已经坚持尝试让它工作好几个小时了。我对编程非常缺乏经验,所以如果我想做的事情完全荒谬,我很抱歉。如果可能的话,为了简单起见,我想避免创建 .txt、.config 或 .JSON(或任何其他不是 .py 的文件)文件来保留变量。

我希望我的程序有一个“经验”变量。在我的整个游戏中,我希望能够在游戏中的任何给定实例的多个不同文件中添加此变量。 (我还希望程序能够在多个模块中使用大约 10 个其他变量)。如果你今天看到我问了一个非常相似的问题,我很抱歉。但我觉得我离解决这个错误越来越近了,但它最终无法正常工作。我很近!

#File1.py
experience = 0
from File2 import givexp
class game:
    def give_xp(self,given_xp):
        global experience
        experience += given_xp
        print('Experience: ',experience)
player = game()
def main():
    print('1) give xp')
    print('2) give 500 xp')
    donow = input()
    if donow == '1':
        givexp() #this is in File2.py
    if donow == '2':
        player.give_xp(500)
while 1:
    main()
#File2.py
def givexp():
    from main import player
    player.give_xp(200)

现在这给我的唯一问题是,当我第一次按 1 时,程序问我要做什么,什么也没发生,它又问我要做什么。我认为这是因为 File2 中的 import 语句。所以当我添加

if __name__ == '__main__':
    while 1:
        main()

这完全弄乱了程序,现在这两个文件将有自己的经验变量,我无法理解。 我知道我可以将我的类更改为常规函数并返回经验,但在我的实际游戏中,将有更多变量需要跟踪,我想以其他方式进行比拥有“var1, var2, var3, etc = part_one_of_game()

现在,这段代码的一切都完全按照我想要的方式运行,除了那个讨厌的错误,即游戏在第一次运行时两次询问玩家他或她想要做什么。有没有简单的解决方法?

【问题讨论】:

  • 我不明白if __name__ == '__main__':有什么问题
  • 我对此感到困惑。当它在那里时,程序不会经过两次“你想做什么”阶段,但 File1 和 File2 会有两个完全独立的变量来体验。如果没有“if name....”条件,我可以继续添加经验(不转到 File2),但第二次按“1”(转到 File2),我的经验重置为 0 . 但是,File1 和 File2 的体验变量是相同的,这是我想要得到的。
  • @KyleMe 如果您要跨会话存储值,请检查阴影解决方案。如果您根本不关心该检查 Olegs 解决方案。但是据我了解,您正在研究如何在“重新启动”(会话)之间保存 10 个变量,如果是这样,pickle.load() 是您的毒药,无论是那个还是 SQLite 数据库(甚至是适当的数据库)。 注意: pickle 在较新的版本中也可以.dump() 类对象,因此将所有 10 个值存储在一个类中,然后转储类就完成了。
  • @Torxed 太棒了。我会记住这一点。当我(最终开始制作)游戏的保存文件时,我很可能会使用保存每个单独变量然后使用不同模块加载它的方法。这听起来简单多了。但是,我只需要在保存文件之前获得游戏的功能。

标签: python class python-3.x scope


【解决方案1】:

您可以为此使用内置的pickle module

用法:

import pickle

# to save variable state
with open('state.pickle', 'w+') as f:
    pickle.dump([x, y, z], f)

# to load variable state
with open('state.pickle', 'r') as f:
    x, y, z = pickle.load(f)

其中 - x、y、z - 是您要保存/加载的变量。

【讨论】:

  • 我看不到 Kyle Me 在哪里询问保存/加载过程。这不回答问题。
  • @oleg - Q 的前两段询问如何在跨多个文件的程序中使用变量的值。保存/加载变量状态是实现此目的的简单方法。此外,Q 要求在整个运行时相应地更改变量值的方法。但是,我确实承认 Q 的最后一段提出了一个完全不同的 Q。也许 OP 应该澄清 Q?
  • @oleg: OP 写道:"py) file to keep variables for simplicity's sake.",他想避免使用 .config 文件或 json 文件。我理解这是因为解析起来很麻烦(有点,或者至少是 OP 体验像这样)。然而,一个 pickle 文件正是 OP 所需要的,一个可以轻松修改和存储的内存“转储”。
  • 不,他只是想在模块之间共享他的程序内的数据。只需使用相同的实例从不同的方法/函数进行操作,他不想使用磁盘上的文件通过它进行通信。
  • @oleg 看到 Python 中的所有变量是如何被全局访问的,他甚至提到了 .config 和 .json 文件,我想说他最终想要存储它们。而且人们对我的许多投票都投了反对票次:“OP 没有问如何被击中脚,这并不意味着我们应该给他这样做的代码”,pickle 是游戏变量的好方法,将它们存储在一个类中是一个很好的基础规则,将两者结合给出最佳答案。
【解决方案2】:

我认为循环导入不是一个好主意,因为这会导致分层问题。

最好将game 类移出__main__ 模块

至于您的问题考虑使用game 属性来存储变量以跟踪

# game.py
class Game(object):
    def __init__(self):
        self.experience = 0
    def give_xp(self,given_xp):
        self.experience += given_xp
        print('Experience: ',experience)

#File2.py
def givexp(player):
    player.give_xp(200)

#File1.py
from game import Game
player = Game()
def main():
    print('1) give xp')
    print('2) give 500 xp')
    donow = input()
    if donow == '1':
        givexp(player) #this is in File2.py
    if donow == '2':
        player.give_xp(500)
if __name__ == '__main__':
    while 1:
        main()

【讨论】:

  • 注意:这不会存储会话之间的值。
  • 看不到这是在哪里问的?
  • “OP 没有要求被击中脚,并不意味着我们应该给他这样做的代码。”, - 引用我收到的所有内容当给予足够解决手头的问题时投反对票。你是对的,上面的代码可以解决问题,一个更好的方法是指示 OP 如何保存它们,同时考虑到它的游戏变量和那些是要保存的(它们通常决定进度和 99 % 的游戏保存会话以便稍后继续)。您对一个可行的解决方案投了反对票,尽管它并不完全符合我认为错误的 OP 要求。
  • Oleg 是正确的,我只是想通过模块来切换它们。我目前正在尝试你的代码,Oleg,我想你可能是第一个回答我的问题的人(终于!)。我非常感激。我正在努力将代码修复到没有任何错误的地方。 (我只是复制粘贴了你的代码)
  • @Torxed 虽然有保存功能很好,但目前这有点超出了我的能力。虽然我很欣赏 Shadow 的建议,但对于我来说理解它的工作原理有点太复杂了(尽管我确信它确实有效)。
【解决方案3】:

这里是one.py

from game import gamehandle
from two import givexp
def main():
    print('1) give xp')
    print('2) give 500 xp')
    print('3) Show current XP')
    donow = input()
    if donow == '1':
        givexp(200) #this calls the function in two.py
    elif donow == '2':
        gamehandle.give_xp(500)
    elif donow == '3':
        print(gamehandle.experience)
if __name__ == '__main__':
    while 1:
        main()

这里是two.py

from game import gamehandle
def givexp(ammount):
    gamehandle.load_variables()
    gamehandle.give_xp(ammount)

最后,game.py

import pickle
from os.path import isfile
class Game(object):
    def __init__(self):
        self.experience = 0
        self.health = 0
        self.loadedFromDisk = False
    def give_xp(self, given_xp):
        self.experience += given_xp
    def save_variables(self):
        with open('game.dump', 'wb') as fh:
            pickle.dump({'xp' : self.experience, 'hp' : self.health}, fh)
    def load_variables(self):
        if not self.loadedFromDisk:
            if isfile('game.dump'):
                with open('game.dump', 'rb') as fh:
                    data = pickle.load(fh)
                    self.experience = data['xp']
                    self.hp = data['hp']
            self.loadedFromDisk = True

gamehandle = Game()

拨打python3 one.py开始游戏。
文件的命名约定很糟糕,我得说.. 但它有效。

这里你可以通过gamehandle直接修改游戏变量,它是Game()类的一个全局实例,它可以在所有已经导入from game import gamehandle的文件中访问。您还可以通过调用“即时”保存和加载变量:

gamehandle.save_variables()

gamehandle.load_variables()

与给出的其他示例相比,此语法有效且经过测试...
我还要说这是访问Game 实例的更好方法,因为您可以简单地执行from game import gamehandle 来访问它,而不是传递它,这使得事情变得更容易并且跟踪实例是一个与微风相比,假设通过 5 个嵌套函数传递它。

作为最后一点,考虑从一开始就将self.experience 更改为字典以节省时间和工作,因为最终您可能希望通过字符串访问变量,这样做会更干净一本字典。

【讨论】:

  • 很好的答案!您已经结合了数据存储和类,并提供了最终的源代码。
  • @shadow Yepp,所以我给了你一个 +1 的想法。
  • 我也给了你一个 +1 - 我喜欢你简洁的实现!
【解决方案4】:

好问题,揭示了一个重要的“问题”。每个模块都有自己的命名空间。即使您导入文件 2,命名空间也会出现 intactisolated。这种隔离很好,因为您可以在两个模块中拥有相同名称的函数。这就是这里的问题:您已经导入了 File 2,它仍然在自己的命名空间中查找变量。错误向我们展示了这一点:

Traceback (most recent call last):
  File "File1.py", line 19, in <module>
    main()
  File "File1.py", line 15, in main
    givexp() #this is in File2.py
  File "/home/pi/File2.py", line 3, in givexp
    player.give_xp(200)
NameError: global name 'player' is not defined

您可以使用可爱的global 关键字来解决这个问题。但是,嘿,你在类的正确轨道上,所以只要确保模块 2 中的函数在你的实例上工作,在这种情况下 player 即将player 传递给函数:

givexp(player)

并更改 File2 以便您的函数接受对象:

#File2.py                                                                       
def givexp(obj):
    obj.give_xp(200)

【讨论】:

    猜你喜欢
    • 2011-04-01
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 2011-05-16
    相关资源
    最近更新 更多