具体示例:是否可以避免使用全局变量?

时间:2017-07-07 09:41:26

标签: python python-3.x variables global local

我有以下程序,所讨论的变量(字典)是 player_info ,用于存储玩家信息(名称和目标)。为了解决当前导致的错误,我只需要将player_info设为全局变量,但我想知道stackoverflow专家是否可以建议或讨论解决此问题的替代方法的可能性不使用全局变量。

代码

#FOOTBALL COACH app

#The program allows a user to enter a number of players (their names and goals scored) and then search for a player, returning their average goals for the three matches


import sys 
def main():
 mainmenu()

def mainmenu():

  print("=====WELCOME to the MAIN MENU=============")
  print("""
  1..........Add New Players & Goals
  2..........Search by Players
  3..........Quit

  =========================================
  """)

  choice=int(input("Enter choice:"))
  if choice==1:
    addplayers()
  elif choice==2:
    searchplayer(player_info)
  elif choice==3:
    sys.exit()
  else:
    print("You must make a valid choice - 1, 2 or 3")


def addplayers():


  player_info= {} #create a dictionary that stores the player name: player goals

  num_players = int(input("Please enter number of players you wish to enter:"))
  print ("You are entering %s players" %num_players)
  player_data = ['Match 1 goals : ', 'Match 2 goals : ', 'Match 3 goals : ']
  for i in range(0,num_players):
      player_name = input("Enter Player Name :")
      player_info[player_name] = {}
      for entry in player_data:
          player_info[player_name][entry] = int(input(entry)) #storing the marks entered as integers to perform arithmetic operations later on.


  mainmenu()


def searchplayer():  
   print("===============SEARCH by player: Calculate average goals==================")
   name = input("Player name : ")
   if name in player_info.keys():
     #print student_info
      print ("Average player goals : ", str(sum(player_info[name].values())/3.0))
   else:
      print("Please enter a valid player name:")

main()

如前所述,我知道在addplayer()sub中重写这个可以解决问题:

global player_info
player_info = {} #create a dictionary that stores the player name: player goals

...我正在寻找解决问题的方法,而不使用全局变量。

更新

使用return player_info下面的一个答案是我想要的,但它还没有完成。此外,每次添加播放器时我都需要返回主菜单,不太确定如何执行此操作,每次都没有主菜单调用。有什么建议? https://repl.it/JRl5/1

3 个答案:

答案 0 :(得分:2)

您可以在函数内使用return以避免使用全局变量。一个简单的例子如下所示:

def addplayers():

    player_info= {} 

    name = input("Enter Name: ")
    test = int(input("Enter a number: "))

    player_info[name] = test

    return player_info


player_info = addplayers()

如果你想在另一个函数中使用它,你只需将字典作为该函数的参数传递:

def searchplayers(player_info):

    print (player_info)

注意:关于" Why are global variables evil?"

的有趣答案

编辑:

您的addplayers()正在调用mainmenu()mainmenu()正在mainmenu内呼叫。这是一个递归函数,除非有充分的理由,否则最好避免使用它们。我会将while的内容放在main循环中,直到满足某些条件。完整的代码如下所示(我删除了def mainmenu(): stop = False while stop == False: print("=====WELCOME to the MAIN MENU=============") print(""" 1..........Add New Players & Goals 2..........Search by Players 3..........Quit ========================================= """) choice=int(input("Enter choice:")) if choice==1: player_info = addplayers() elif choice==2: searchplayer(player_info) elif choice==3: print ("Exit the main menu") stop = True else: print("You must make a valid choice - 1, 2 or 3") def addplayers(): player_info= {} #create a dictionary that stores the player name: player goals num_players = int(input("Please enter number of players you wish to enter:")) print ("You are entering %s players" %num_players) player_data = ['Match 1 goals : ', 'Match 2 goals : ', 'Match 3 goals : '] for i in range(0,num_players): player_name = input("Enter Player Name :") player_info[player_name] = {} for entry in player_data: player_info[player_name][entry] = int(input(entry)) #storing the marks entered as integers to perform arithmetic operations later on. return player_info def searchplayer(player_info): print("===============SEARCH by player: Calculate average goals==================") name = input("Player name : ") if name in player_info.keys(): #print student_info print ("Average player goals : ", str(sum(player_info[name].values())/3.0)) else: print("Please enter a valid player name:") mainmenu() 函数,因为它没有做任何事情):

<ComboBox fx:id="select_pc" promptText="Select PC">
            <HBox.margin>
               <Insets left="20.0" top="35.0" />
            </HBox.margin>
            <items>
                <FXCollections fx:factory="observableArrayList">
                    <String fx:value="ForkLift" />
                    <String fx:value="Gates" />
                </FXCollections>
            </items>
        </ComboBox>

答案 1 :(得分:0)

将与游戏相关的所有内容存储在数据结构中,例如字典,并将其传递到可根据需要更新的所有功能中。写一个函数&#34; newgame&#34;创建这个结构并初始化它。

在某种程度上,这是面向对象的编程,而不使用Python的类和对象语法。或许,您将在课程/教程中学习这些内容。

答案 2 :(得分:0)

首先,始终可以避免使用全局变量。其次,全局变量在Python中可能是用词不当; global将变量存储在本地globals中,这通常是本地模块。这避免了大部分问题语言,如C语言与全局语言,因为它们发生碰撞; Python每个模块都有一个命名空间。对于一个简单的脚本,只有一个上下文,可能没问题。

您可能使用的另一个名称空间是使用类的特定对象的名称空间。这可能看起来像:

class Game:
    def mainmenu(self,...):
        self.addplayers()
    def addplayers(self):
        self.player_info = {}

使用那种代码,无论谁实例化Game都可以创建多个实例,每个实例在使用时都会以self传递。对于类似形式的可变状态传递,这在很大程度上是语法糖:

def mainmenu():
    state={}
    addplayers(state)
def addplayers(state):
    state['player_info'] = {}

对于某些形式的编程,不可变状态是更可取的(特别是多线程,其中数据是共享的,或者保存日志,您可以在其中撤消步骤)。这样做的方式类似,但每次调用都会创建一个新状态:

def mainmenu():
    state = {}
    state = addplayers(state)
def addplayers(oldstate):
    newstate = oldstate.copy()
    newstate['player_info'] = {}
    return newstate

Python不是为此设计的,并没有真正的模式来防止您无意中修改可变类型。某些类型可以转换为不可变的类似类型,如frozensettuple

我们可以做的一个怪异的黑客攻击是用一组不同于通常的全局变量来调用Python函数。这可以被滥用来获取现有函数,global语句和所有函数,并让它们使用不同的变量:

fakeglobals = mainmenu.__globals__.copy()
exec(addplayers.__code__, fakeglobals)

您的原始代码在函数之间来回调用,并且每个代码都会根据__globals__属性重置其全局变量。

您的代码还使用尾递归实现循环。这在Python中没有优化,最终会耗尽堆栈空间。在优化尾递归的语言中,您可以连续传递状态作为参数,而无需返回它。