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

2024-05-01 22:11:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我有下面的程序和变量(字典)是存储玩家信息(姓名和目标)的player\u 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()子文件中重新编写此文件可以解决问题:

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

…我正在寻找不使用全局变量的方法来解决问题。你知道吗

更新:

下面使用return player\ u info的一个答案是我想要的,但它还没有完全起作用。另外,我需要返回到主菜单每次球员被添加,不太清楚如何做到这一点,没有主菜单调用每次。有什么建议吗?https://repl.it/JRl5/1


Tags: thetonameinfoforinputdefplayer
3条回答

可以在函数中使用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()

首先,总是可以避免使用全局变量。其次,全局变量在Python中可能是一个误称;global将变量存储在局部全局变量中,这通常是局部模块。这就避免了像C这样的语言与globals之间的大部分问题,因为它们会发生冲突;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集合与通常的不同。这可能会被滥用以获取现有函数、global语句和所有语句,并让它们使用不同的变量:

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

但是,您的原始代码在函数之间来回调用,每个函数都将根据__globals__属性重置其全局变量。你知道吗

您的代码还使用尾部递归实现了一个循环。这在Python中没有优化,最终将耗尽堆栈空间。在优化尾部递归的语言中,可以连续地将状态作为参数传递,而不需要返回它。你知道吗

将所有与游戏相关的内容存储在一个数据结构中,例如一个字典,并将其传递到所有函数中,以便根据需要进行更新。编写一个函数“newgame”来创建这个结构并初始化它。你知道吗

在某种程度上,这是面向对象的编程,而不使用Python的类和对象语法。也许,你会在以后的课堂/教程中学习这些。你知道吗

相关问题 更多 >