具体示例:是否可以避免使用全局变量?
Specific example: Is it possible to aviod the use of a global variable?
我有以下程序,有问题的变量(字典)是 player_info,它存储玩家信息(姓名和目标)。为了解决当前导致的错误,我只需要将 player_info 设置为 全局变量 ,但我想知道 Whosebug 专家是否可以建议或讨论替代方法的可能性解决此问题的方法 不使用全局变量。
代码
#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_info 的一个答案是我想要的,但它还不太奏效。此外,每次添加播放器时我都需要 return 到主菜单,不太确定如何执行此操作,每次都没有调用主菜单。有什么建议么? https://repl.it/JRl5/1
您可以在函数内部使用 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()
将与游戏相关的所有内容存储在数据结构中,例如字典,并将其传递到所有可以根据需要更新的函数中。编写一个函数 "newgame" 来创建这个结构并对其进行初始化。
在某种程度上,这是面向对象的编程,不使用 Python 的 class 和对象的语法。也许,您稍后会在 class / 教程中学习这些内容。
首先,总是可以避免使用全局变量。其次,全局变量在Python中可能用词不当; global
将变量存储在本地全局变量中,通常是本地模块。这避免了像 C 这样的语言与全局变量的大部分问题,因为它们会发生冲突; Python 每个模块有一个名称space。对于只有一个上下文的简单脚本,这可能没问题。
您可能使用的另一个名称space 是特定对象的名称,使用 class。这可能看起来像:
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 不是为此设计的,也没有真正的模式来防止您无意中修改可变类型。某些类型可以转换为类似的不可变类型,例如 frozenset
或 tuple
。
我们可以做的一个更奇怪的 hack 是调用一个 Python 函数,使用一组与通常不同的全局变量。这可能会被滥用来获取您现有的函数、global
语句和所有这些,并让它们使用不同的变量:
fakeglobals = mainmenu.__globals__.copy()
exec(addplayers.__code__, fakeglobals)
不过,您的原始代码在函数之间来回调用,并且每个函数都会根据 __globals__
属性重置它们的全局变量。
您的代码还使用尾递归实现了一个循环。这在 Python 中没有优化,最终会 运行 出栈 space。在优化尾递归的语言中,您可以连续传递状态作为参数,而不需要 return 它。
我有以下程序,有问题的变量(字典)是 player_info,它存储玩家信息(姓名和目标)。为了解决当前导致的错误,我只需要将 player_info 设置为 全局变量 ,但我想知道 Whosebug 专家是否可以建议或讨论替代方法的可能性解决此问题的方法 不使用全局变量。
代码
#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_info 的一个答案是我想要的,但它还不太奏效。此外,每次添加播放器时我都需要 return 到主菜单,不太确定如何执行此操作,每次都没有调用主菜单。有什么建议么? https://repl.it/JRl5/1
您可以在函数内部使用 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()
将与游戏相关的所有内容存储在数据结构中,例如字典,并将其传递到所有可以根据需要更新的函数中。编写一个函数 "newgame" 来创建这个结构并对其进行初始化。
在某种程度上,这是面向对象的编程,不使用 Python 的 class 和对象的语法。也许,您稍后会在 class / 教程中学习这些内容。
首先,总是可以避免使用全局变量。其次,全局变量在Python中可能用词不当; global
将变量存储在本地全局变量中,通常是本地模块。这避免了像 C 这样的语言与全局变量的大部分问题,因为它们会发生冲突; Python 每个模块有一个名称space。对于只有一个上下文的简单脚本,这可能没问题。
您可能使用的另一个名称space 是特定对象的名称,使用 class。这可能看起来像:
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 不是为此设计的,也没有真正的模式来防止您无意中修改可变类型。某些类型可以转换为类似的不可变类型,例如 frozenset
或 tuple
。
我们可以做的一个更奇怪的 hack 是调用一个 Python 函数,使用一组与通常不同的全局变量。这可能会被滥用来获取您现有的函数、global
语句和所有这些,并让它们使用不同的变量:
fakeglobals = mainmenu.__globals__.copy()
exec(addplayers.__code__, fakeglobals)
不过,您的原始代码在函数之间来回调用,并且每个函数都会根据 __globals__
属性重置它们的全局变量。
您的代码还使用尾递归实现了一个循环。这在 Python 中没有优化,最终会 运行 出栈 space。在优化尾递归的语言中,您可以连续传递状态作为参数,而不需要 return 它。