如何在函数内保留 运行 总数并允许在函数外访问它?

How to keep a running total inside a function and allow it to be accessed outside of the function?

我想保留 运行 用户摄入的总卡路里数,然后将其插入数据库,同时提供用户摄入卡路里量的反馈。当我在函数外定义 TotalCalories 并将其设置为全局变量(以便它可以在另一个函数内使用)时,我得到错误 UnboundLocalError: local variable 'TotalCalories' referenced before assignment

def FoodSelection(choice):
    global CurrentPupil
    CurrentPupil = ""
    global FoodSelectionWindow
    FoodSelectionWindow = Toplevel()
    FoodSelectionWindow.configure(bg="black")

    DateAdded = datetime.date.today()
    TimeTaken = 0
    NoFoodOption = 0

    #The validation timer starts here:

    while TimeTaken < 2:
        time.sleep(60)
        TimeTaken = TimeTaken +1

    #and ends here

    class food():
        def __init__(self, name = "no name", calories = 0, photo = ""):
            self.name = name
            self.calories = calories
            self.photo = photo

    BoiledEggs = food("Boiled Egg", 155, PhotoImage(file="BoiledEgg.gif"))
    ScrambledEggs = food("Scrambled Egg", 148, PhotoImage(file="ScrambledEgg.gif"))
    FriedEggs = food("Fried Egg", 196, PhotoImage(file="FriedEgg.gif"))
    PoachedEggs = food ("Poached Egg", 143, PhotoImage(file="PoachedEgg.gif"))
    Toast = food("Toast", 313, PhotoImage(file="Toast.gif"))
    Bacon = food("Bacon", 514, PhotoImage(file="Bacon.gif"))
    Cereal = food("Cereal", 379, PhotoImage(file="Cereal.gif"))
    Porridge = food("Porridge", 68, PhotoImage(file="Cereal.gif"))
    NoBreakfast = food("No Breakfast", 0, PhotoImage(file="NoBreakfast.gif"))

    def NoFood():
        FoodChoices("No Food")

    def BoiledEggsFunct():
        FoodChoices("Boiled Eggs")

    def FriedEggsFunct():
        FoodChoices("Fried Eggs")

    def ScrambledEggsFunct():
        FoodChoices("Scrambled Eggs")

    def PoachedEggsFunct():
        FoodChoices("Poached Eggs")

    def ToastFunct():
        FoodChoices("Toast")

    def BaconFunct():
        FoodChoices("Bacon")

    def CerealFunct():
        FoodChoices("Cereal")

    def PorridgeFunct():
        FoodChoices("Porridge")

    global TotalCalories
    TotalCalories = 0

    def FoodChoices(selection):

        if selection == "No Food":
            TotalCalories = NoBreakfast.calories

        elif selection == "Boiled Eggs":
            TotalCalories = BoiledEggs.calories + TotalCalories

        elif selection == "Fried Eggs":
            TotalCalories = FriedEggs.calories + TotalCalories

        elif selection == "Scrambled Eggs":
            TotalCalories = ScrambledEggs.calories + TotalCalories

        elif selection == "Poached Eggs":
            TotalCalories = PoachedEggs.calories + TotalCalories

        elif selection == "Toast":
            TotalCalories = Toast.calories + TotalCalories

        elif selection == "Bacon":
            TotalCalories = Bacon.calories + TotalCalories

        elif selection == "Cereal":
            TotalCalories = Cereal.calories + TotalCalories

        elif selection == "Porridge":
            TotalCalories = Porridge.calories + TotalCalories


        if choice == 'chris':
            CurrentPupil = "Chris"
            with db:
                cursor.execute(''' INSERT INTO 'Breakfast_History' (CaloriesTotal, DateAddded, PupilNames, PupilID) VALUES (?,?,?,?)''',
                               ([TotalCalories, DateAdded, CurrentPupil,"1"]))
        elif choice == 'josh':
            CurrentPupil = "Josh"
            with db:
                cursor.execute(''' INSERT INTO 'Breakfast_History' (CaloriesTotal, DateAddded, PupilNames, PupilID) VALUES (?,?,?,?)''',
                           ([TotalCalories, DateAdded, CurrentPupil,"2"]))
        elif choice == 'sam':
            CurrentPupil = "Sam"
            with db:
                cursor.execute(''' INSERT INTO 'Breakfast_History' (CaloriesTotal, DateAddded, PupilNames, PupilID) VALUES (?,?,?,?)''',
                           ([TotalCalories, DateAdded, CurrentPupil,"3"]))
        elif choice == 'daniel':
            CurrentPupl = "Daniel"
            with db:
                cursor.execute(''' INSERT INTO 'Breakfast_History' (CaloriesTotal, DateAddded, PupilNames, PupillID) VALUES (?,?,?,?)''',
                           ([TotalCalories, DateAdded, CurrentPupil, "4"]))
        elif choice == 'jim':
            CurrentPupil = "Jim"
            with db:
                cursor.execute(''' INSERT INTO 'Breakfast_History' (CaloriesTotal, DateAddded, PupilNames, PupilID) VALUES (?,?,?,?)''',
                           ([TotalCalories, DateAdded, CurrentPupil,"5"]))

        elif choice == 'sean':
            CurrentPupil = "Sean"
            with db:
                cursor.execute(''' INSERT INTO 'Breakfast_History' (CaloriesTotal, DateAddded, PupilNames, PupilID) VALUES (?,?,?,?)''',
                           ([TotalCalories, DateAdded, CurrentPupil,"6"]))

        db.commit()

    def FeedbackScreen():
        FinishWindow = Toplevel()

        if TotalCalories > 0 and TotalCalories < 1000:
            HealthyLabel = Label(FinishWindow, text = "Congratulations, you are healthy!", font=("Comic Sans MS", 25), fg = "light green",
                  bg = "black")
            HealthyLabel.grid(columnspan=10)

        elif TotalCalories > 1000:
            UnhealthyLabel = Label(FinishWindow, text = "Try to eat healthier tomorrow. See personalised advice", font=("Comic Sans MS", 25), fg = "yellow",
                  bg = "black")
            UnhealthyLabel.grid(columnspan=10)

        elif NoFoodOption == 1:
            NoFoodLabel = Label(FinishWindow, text = "Not eating can be harmful to your health. See personalised advice", font=("Comic Sans MS", 25), fg = "red",
                  bg = "black")
            NoFoodLabel.grid(columnspan=10)

        else:
            Error = Label(FinishWindow, text = "error", font=("Comic Sans MS", 25), fg = "red",
                  bg = "black")
            NoFoodLabel.grid(columnspan=10)    

如您所见,我需要在整个代码中的各种函数中使用 TotalCalories,因此我认为通过将其设为全局变量,我可以做到这一点。

有什么建议吗?

这是MCVE你的问题:

global TotalCalories
TotalCalories = 0

def FoodChoices(selection):

    if selection == "No Food":
        TotalCalories = 100

    elif selection == "Boiled Eggs":
        TotalCalories = 100 + TotalCalories

FoodChoices("Boiled Eggs")

运行 此代码产生此输出:

$ python test.py
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    FoodChoices("Boiled Eggs")
  File "test.py", line 11, in FoodChoices
    TotalCalories = 100 + TotalCalories
UnboundLocalError: local variable 'TotalCalories' referenced before assignment

并在函数中插入 global TotalCalories 使其消失:

def FoodChoices(selection):
    global TotalCalories

    if selection == "No Food":
        TotalCalories = 100

    elif selection == "Boiled Eggs":
        TotalCalories = 100 + TotalCalories

Python 要求在要使用它的函数中声明一个全局名称,如果您打算重新绑定全局。如果您只是从中读取或改变它,那么您可以在函数中不声明。

您可能没有考虑过替代方案。在 Python 中,出于某些目的,您可以使对象看起来像函数。然后,您可以积累在对象变量中调用函数时收集到的信息。那么在您的情况下, TotalCalories 可能是对象中的变量。诀窍是为对象中的方法使用名称 __call__;变成 'callable'.

class FoodSelection:
    def __init__ (self):
        self.TotalCalories = 0
    def __call__ (self, choice):
        if choice == 'potatoes':
            print (choice, ''': eat as little as possible!''')
            self.TotalCalories += 10000
        elif choice == 'salad':
            print (choice, ': good choice!')
            self.TotalCalories += 0
        else:
            print (choice, ''': sorry, don't understand that''')


foodSelection = FoodSelection()

foodSelection('potatoes')
print (foodSelection.TotalCalories)

foodSelection('salad')
print (foodSelection.TotalCalories)

foodSelection('bacon')
print (foodSelection.TotalCalories)

foodSelection('potatoes')
print (foodSelection.TotalCalories)

这是输出:

potatoes : eat as little as possible!
10000
salad : good choice!
10000
bacon : sorry, don't understand that
10000
potatoes : eat as little as possible!
20000