全局变量问题 - Python

时间:2011-03-27 02:46:19

标签: python tkinter

我遇到全局变量的困难。

我的代码:

from Tkinter import *
import Tkinter as tk
import tkMessageBox
import time
import re
import string
from random import randint
class prgrm():

    def start():
        global bs
        global bsrly
        global bsrly2
        global turns
        global rec
        global exp
        global word
        global x
        global w
        global guess
        print "Hangman v1.7 - by Josh & Paul"
        bsrly2 = False
        bsrly = False
        notlie = True
        turns = 8
        rec = ''
        exp = '^[a-z]+$'
        textfile = open('dictionary.txt', 'r')
        words = ['j']
        n = randint(0, len(words)-1)
        word = words[n]
        x = 0
        w = list(word)
        guess = ''
        bs = ''
        for letter in word:
            if letter in guess:
                bs += letter + ' '
            else:
                bs += '_ '

        bs = bs.upper()
        first()


    def MainProgram():
        global ui
        global guess
        global turns
        global rec
        global bs
        global bsrly
        global bsrly2
        bs = ''
        inp = ui.get().strip()
        inp = inp.lower()
        ui.delete(0, END)
        if bsrly2 == True:
            root.quit()

        if inp == "":
            tkMessageBox.showerror("Incorrect Entry", "Error: Please enter a letter")

        elif inp in guess:
            tkMessageBox.showerror("Incorrect Entry", "Error: You have already tried that letter")

        elif not re.match(exp, inp):
            tkMessageBox.showerror("Incorrect Entry", "Error: Please enter a letter")




        else:
            if inp not in word:
                turns -= 1

            if turns == 7:
                img.configure(image=image0)
            if turns == 6:
                img.configure(image=image1)
            if turns == 5:
                img.configure(image=image2)
            if turns == 4:
                img.configure(image=image3)
            if turns == 3:
                img.configure(image=image4)
            if turns == 2:
                img.configure(image=image5)
            if turns == 1:
                img.configure(image=image6)

            guess += ' ' + inp
            if turns == 0:
                img.configure(image=image7)
                bsrly2 = True

            if inp not in word:
                upd.configure(text= "Wrong, try again")
                rec += ' ' + inp
            if inp in word:
                upd.configure(text= "Thats correct!")

            guess2 = rec.upper()
            fb2.configure(text = "Wrong letters:" + guess2)

            wait = 0
            left = 0
            for letter in word:
                if letter in guess:
                    bs += letter + " "
                else:
                    bs += '_ '
                    left += 1

            bs = bs.upper()
            if left == 0:
                bsrly = True
            feedback.configure(text=bs)
            bs = ''
            if bsrly2 == True:
                root
                upd.configure(text="You lose, the word was " + word)

            check()
    def check():
        if bsrly == True:
            root.destroy()
            root2 = Tk()
            root2.wm_iconbitmap('hmn.ico')
            root2.title("You Win!")
            youwin = tk.PhotoImage(master=root2, file="YouWin.gif")
            winer = Label(master=root2, image=youwin)
            winer.image = youwin
            winer.grid(row=0, rowspan=20)
            wanaquit = Label(master=root2, text="Play Again?")
            wanaquit.grid(row=21)
            pbuton = Button(master=root2, text="Yes", command=start)
            pbuton.grid(row=22)
            root2.mainloop()
    global val      
    def val(i):
        if int(i) > 0:
          return False
        return True

    def first():
        global bs
        root = Tk()
        root.wm_iconbitmap('hmn.ico')
        root.title("Hangman v1.7")
        vcmd = (root.register(val), '%i')
        image = tk.PhotoImage(file="image.gif")
        image0 = tk.PhotoImage(file="image0.gif")
        image1 = tk.PhotoImage(file="image1.gif")
        image2 = tk.PhotoImage(file="image2.gif")
        image3 = tk.PhotoImage(file="image3.gif")
        image4 = tk.PhotoImage(file="image4.gif")
        image5 = tk.PhotoImage(file="image5.gif")
        image6 = tk.PhotoImage(file="image6.gif")
        image7 = tk.PhotoImage(file="image7.gif")
        content = tk.Frame(root, bg='black')
        namelbl = tk.Label(content, text="Enter a letter:", bg="black", fg="green")
        feedback = tk.Label(content, text=bs, bg="black", fg="green")
        rb = tk.Checkbutton(content, text="Music", bg="black", fg="green")
        slave = tk.Label(content, text="", bg="black", fg="green")
        slave2 = tk.Label(content, text="", bg="black", fg="green")
        upd = tk.Label(content, text="", bg="black", fg="green")
        fb2 = tk.Label(content, text="Used letters:", bg="black", fg="green")
        ui = tk.Entry(content, validate="key", validatecommand=vcmd)
        ui["width"] = 2
        img = tk.Label(master=content, image=image, bg="black")
        ok = tk.Button(content, text="Okay", bg="black", fg="green", command=MainProgram)
        ui.focus()
        ui.bind('<Return>', (lambda e: MainProgram()))
        content.grid(column=0, row=0)
        img.grid(column=0, row=0, columnspan=4)
        feedback.grid(column=0, row=1)
        fb2.grid(column=0, row=2)
        slave.grid(row=3)
        slave2.grid(row=5)
        upd.grid(row=4, columnspan=4)
        namelbl.grid(column=0, row=6)
        ui.grid(column=1, row=6, sticky=W)
        ok.grid(column=1, row=6)
        rb.grid(row=7)
        root.mainloop()
    first()

start()

我疯了,因为它继续说“全局变量'bs'没有被定义'等等。我该怎么办?请和我一起讨厌:)

4 个答案:

答案 0 :(得分:3)

解决问题的最佳方法:消除全局变量并将它们作为参数传递给手头的方法,或者传递给之前调用的方法(例如构造函数),并将它们设置在类中。

所以而不是:

class Foo:
    def test():
        global a
        global b
        global c

...等。

执行:

class Foo:
    a = 0
    b = 0
    c = 0

    def test(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

...等。

或者使用构造函数:

class Foo:
    a = 0
    b = 0
    c = 0

    def __init__(self,a, b, c): 
        self.a = a
        self.b = b
        self.c = c

    def test(self):

...等。

基本上您正在完成的是将代码拆分为组件(类)。您希望将每个类转换为一个本质上具有(或通过方法接收)所需内容的组件,而不是在其他地方使用纠缠联盟(即全局变量)。

它就像一个盒子里面有二十根电缆以不可预测的方式进入它的区别而不是一个盒子,它有一个定义明确的程序来接受通过电缆传递的信息,并清楚地指明一些明确定义和可测试的路线进入其内部。您希望您创建的类/对象尽可能少地与外界联系,以使其可预测,并且易于调试和扩展。将全局变量视为代码盔甲中的穿孔以及许多令人不快的意外的原因。

依赖太多的全局变量可能会导致问题,并且应该避免许多(如果不是全部)情况。

答案 1 :(得分:2)

首先你不应该使用全局变量,除非你真的需要。这不是这种情况。他们是邪恶的:)。检查Mark Nenadov的回答。

但是你的信息。您需要在函数范围外声明变量,然后在函数中使用global关键字(如果需要修改内容)。请参阅此主题Using global variables in a function other than the one that created them

答案 2 :(得分:1)

编辑:显然我不太清楚解释我的动机;

虽然您可以定义足够的全局变量来使您的解决方案正常工作,但它仍然是非常糟糕的做法。以下代码显示了如何正确地来回传递变量,维护封装,使故障排除和维护以及重用更少的麻烦。

您应该能够通过继承Hangman并覆盖输​​入和输出方法来创建Tkinter Hangman。

import random

def canonicalString(s):
    return s.strip().upper()

class Words(object):
    @classmethod
    def fromFile(cls, fname):
        "Create a Words object from a file (containing no more than one word per line)"
        with open(fname) as inf:
            return cls([word for word in (line.strip() for line in inf) if word])

    def __init__(self, words):
        super(Words,self).__init__()
        self.words = [canonicalString(word) for word in words]

    def randWord(self):
        return random.choice(self.words)

class Hangman(object):
    def __init__(self, maxTurns=8):
        super(Hangman,self).__init__()
        self.maxTurns = maxTurns

    def run(self, target):
        self.sayWelcome()
        target  = canonicalString(target)
        guesses = ''
        turn    = 1
        solved  = False
        while turn <= self.maxTurns and not solved:
            while True:
                self.sayState(turn, target, guesses)
                nextGuess = self.getGuess(guesses)
                if nextGuess in target:
                    self.sayGoodGuess(nextGuess)
                    guesses += nextGuess
                    solved = all(ch in guesses for ch in target)
                    if solved:
                        break
                else:
                    self.sayBadGuess(nextGuess)
                    break
            turn += 1
        self.sayState(turn, target, guesses)
        self.saySolved(turn, target, guesses) if solved else self.sayFailed(turn, target, guesses)

    def sayWelcome(self):
        print("Hangman v1.7 - by Hugh & Josh & Paul")

    def sayState(self, turn, target, guesses):
        print("\nTurn #{0}".format(turn))
        print('\n'.join([
            "",
            "",
            "",
            "",
            "",
            "",
            "",
            "",
            "",
            "____________",
            "",
            "",
            "",
            "     O",
            "     +",
            "    /|\ ",
            "     +",
            "    / \ ",
            "",
            "____________",
            "",
            "",
            "     O",
            "     +",
            "    /|\ ",
            "     +     |",
            "    / \    |",
            "           |",
            "           |",
            "___________|",
            "",
            "           |",
            "     O     |",
            "     +     |",
            "    /|\    |",
            "     +     |",
            "    / \    |",
            "           |",
            "           |",
            "___________|",
            "         ----",
            "           |",
            "     O     |",
            "     +     |",
            "    /|\    |",
            "     +     |",
            "    / \    |",
            "           |",
            "           |",
            "___________|",
            "        -----",
            "         \ |",
            "     O    \|",
            "     +     |",
            "    /|\    |",
            "     +     |",
            "    / \    |",
            "           |",
            "           |",
            "___________|",
            "    ---------",
            "         \ |",
            "     O    \|",
            "     +     |",
            "    /|\    |",
            "     +     |",
            "    / \    |",
            "           |",
            "           |",
            "___________|",
            "    ---------",
            "     |   \ |",
            "     @    \|",
            "   --+--   |",
            "     |     |",
            "     +     |",
            "    / \    |",
            "           |",
            "           |",
            "___________|",
            "    ---------",
            "     |   \ |",
            "     |    \|",
            "     |     |",
            "     &     |",
            "     %     |",
            "    /|\    |",
            "     +     |",
            "    / \    |",
            "___________|"        
        ][(turn-1)*10: turn*10]))
        print(' "{0}"'.format(''.join(ch if ch in guesses else '_' for ch in target)))

    def getGuess(self, guesses):
        while True:
            ch = canonicalString(raw_input("Please enter a letter: "))

            if len(ch) != 1:
                print("  One character only!")
            elif not ch.isalpha():
                print("  Must be a letter!")
            elif ch in guesses:
                print("  You already picked it!")
            else:
                return ch

    def sayGoodGuess(self, guess):
        print("Yep, that's one!")

    def sayBadGuess(self, guess):
        print("Say yer prayers, you lown-down side-winder!")

    def saySolved(self, turn, target, guesses):
        print("Ah, shucks - looks like we got the wrong man. Cut 'im loose!")

    def sayFailed(self, turn, target, guesses):
        print("Thet-there's one polecat won't trouble us no more! (Your last word on Earth was {0})".format(target))

def main():
    print("Loading dict... ")
    words = Words.fromFile("dictionary.txt")
    print("done.")

    game = Hangman()
    while True:
        game.run(words.randWord())

        tryagain = raw_input("Try another round? (Y/n)").strip().lower()
        if 'yes'.startswith(tryagain):
            print("Okey-doke...")
        else:
            print("G'bye, pardner!")
            break

if __name__=="__main__":
    main()

答案 3 :(得分:0)

在调用start()之前调用first(),因此变量“bs”确实还没有。也许你打算在start()之后调用first() 虽然不确定...... 也许改变 feedback = tk.Label(content,text = bs,bg =“black”,fg =“green”) 至 feedback = tk.Label(content,text =“?”,bg =“black”,fg =“green”) 因为无论如何你以后更新它。 或者添加一个 BS = “?” 在文件的最开始?