Проблемы с сбросом / возвратом с переменными

#python-2.7 #wxpython

#python-2.7 #wxpython

Вопрос:

Я написал генератор крипто-кавычек на Python, используя wxPython. На самом деле у меня нет никаких проблем с самим wxPython, а скорее с сбросом моих переменных. Моя программа работает следующим образом: у меня есть кнопка, которая генерирует зашифрованную цитату. Затем у пользователя есть кнопка декодирования, которую они нажимают, чтобы изменить по одной букве за раз. Есть кнопка для сброса всей цитаты и кнопка для сброса изменений на один шаг назад за раз.

У меня есть base_copy переменная для хранения исходной зашифрованной цитаты. Это пустой список, который заполняется отдельными символами зашифрованной цитаты по одному при вызове on_generate_quote . Он остается неизменным на протяжении всего цикла — так что я могу вызвать его с помощью on_clear_all или on_clear_last , чтобы сбросить мою зашифрованную цитату. Проблема в том, что если я использую my decode_button для декодирования буквы, затем использую my clear_all_button , затем decode_button снова мои clear_all_button вызовы для base_copy , который теперь каким-то образом испорчен измененными буквами, которые должны быть только в моей split_cryptoquote копии. Почему это, поскольку я никогда не выполняю неявный вызов alter base_copy ? (Тем не менее, я делаю вызов в on_clear_all для установки split_cryptoquote на base_copy , но это не должно измениться base_copy .)

 #/------------------ wxPython GUI -----------------

class MainWindow(wx.Frame):

    quote = []
    quote.append(quote_fetch(quotes))
    split_cryptoquote = []
    base_copy = []
    split_buffer = []
    buffer_origin = None
    buffer_replace = None
    quote_altered = False #Becomes true after first decoding change.

    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title="Cryptogrammar", size=(1000, 200))
        self.CreateStatusBar()

        self.txt = wx.StaticText(self, -1, "".join(MainWindow.split_cryptoquote), (20,30), (40,40))
        self.txt.SetForegroundColour("WHITE")

        #Menu
        filemenu = wx.Menu()
        menu_about = filemenu.Append(wx.ID_ABOUT, "amp;About", " Information about this program")
        menu_how = filemenu.Append(HOW_TO, "amp;How to Play", " How to play Cryptogrammar")
        menu_exit = filemenu.Append(wx.ID_EXIT,"Eamp;xit", " Close Cryptogrammar")
        #menuGenerate = filemenu.Append(wx.ID_NONE, "amp;Generate New", "Generate a new cryptogram")

        #menu_bar
        menu_bar = wx.MenuBar()
        menu_bar.Append(filemenu, "amp;File")
        self.SetMenuBar(menu_bar)


        #Buttons
        generate_button = wx.Button(self, -1, "amp;Generate Cryptogram")
        decode_button = wx.Button(self, -1, "amp;Decode Letter")
        clear_all_button = wx.Button(self, -1, "amp;Clear All Changes")
        clear_last_button = wx.Button(self, -1, "Clear amp;Last Change")
        answer_button = wx.Button(self, -1, "Show amp;Answer")
        but_list = [generate_button, decode_button, clear_all_button, clear_last_button, answer_button]

        #Sizers
        self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
        for i in range(0, 5):
            self.sizer2.Add(but_list[i], 1, wx.EXPAND)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.txt, 1, wx.EXPAND)
        self.sizer.Add(self.sizer2, 0, wx.EXPAND)

        #Events
        self.Bind(wx.EVT_MENU, self.on_about, menu_about)
        self.Bind(wx.EVT_MENU, self.on_exit, menu_exit)
        self.Bind(wx.EVT_MENU, self.on_how, menu_how)
        self.Bind(wx.EVT_BUTTON, self.on_generate_quote, generate_button)
        self.Bind(wx.EVT_BUTTON, self.on_decode, decode_button)
        self.Bind(wx.EVT_BUTTON, self.on_answer, answer_button)
        self.Bind(wx.EVT_BUTTON, self.on_clear_all, clear_all_button)
        self.Bind(wx.EVT_BUTTON, self.on_clear_last, clear_last_button)


        self.SetSizer(self.sizer)
        self.SetAutoLayout(1)
        self.sizer.Fit(self)
        self.SetTitle("Cryptogrammar")
        self.Centre()

    def on_about(self, e):
        dialogue = wx.MessageDialog(self, "A program for generating random cryptograms.nnnnCopyright 2014 Joshua SimmonsnVersion 0.1.0", "About Cryptogrammar", wx.OK)
        dialogue.ShowModal()
        dialogue.Destroy()

    def on_exit(self, e):
        self.Close(True)

    def on_how(self, e):
        dialogue = wx.MessageDialog(self, "HOW TO PLAY:nnn--tPress the 'Generate Cryptogram' to spawn a cryptogram.nn--tUse the 'Decode Letter' to replace an encrypted letter with a letter of your choice. 'Decoded' letters will be lowercase to distinguish them.nn--tUse the 'Clear Changes' button to reset the puzzle.nn--t'Show Answer' solves the puzzle!", "How to play Cryptogrammar", wx.OK)
        dialogue.ShowModal()
        dialogue.Destroy()

    def on_decode(self, e):
        dialogue = wx.TextEntryDialog(self, "Which letter do you wish to change? Use format: 'a=e'", "Decode Letter", "")
        dialogue.ShowModal()
        decode = dialogue.GetValue()
        #Text entry filter
        match = re.search(r'w =w |^d*$', decode)
        if not match:
            err = wx.MessageDialog(self, "That is not a correct entry format.", "Entry Error", style=wx.ICON_HAND)
            err.ShowModal()
            #Letter replacement
        else:
            if not MainWindow.quote_altered:
                MainWindow.buffer_origin = decode[0].upper()
                MainWindow.buffer_replace = decode[2].upper()
            else:
                for n in range(0, len(MainWindow.split_buffer)):
                    if MainWindow.split_buffer[n] == MainWindow.buffer_origin:
                        MainWindow.split_buffer[n] = MainWindow.buffer_replace.lower()
                MainWindow.buffer_origin = decode[0].upper()
                MainWindow.buffer_replace = decode[2].upper()
            origin = decode[0].upper()
            replace = decode[2].upper() #For resetting changes one at a time.
            for n in range(0, len(MainWindow.split_cryptoquote)):
                if MainWindow.split_cryptoquote[n] == origin:
                    MainWindow.split_cryptoquote[n] = replace.lower()
            MainWindow.quote_altered = True
            origin = None
            replace = None
            self.txt.SetLabel("".join(MainWindow.split_cryptoquote))
            self.sizer.Layout()


        dialogue.Destroy()

    def on_generate_quote(self, e):

        MainWindow.quote.pop()
        MainWindow.quote.append(quote_fetch(quotes))
        cryptoquote = generate_cryptogram(MainWindow.quote[0], encrypt_key(shuffle_alphabet()))
        MainWindow.split_cryptoquote = []
        MainWindow.base_copy = []
        for i in cryptoquote:
            MainWindow.split_cryptoquote.append(i)
            MainWindow.base_copy.append(i)
            MainWindow.split_buffer.append(i)
        self.txt.SetLabel("".join(MainWindow.split_cryptoquote))
        self.txt.SetForegroundColour("BLACK")
        self.sizer.Layout()

    def on_answer(self, e):
        if len(MainWindow.base_copy) == 0:
            err = wx.MessageDialog(self, "You haven't generated a puzzle yet, doofus!", "Encryption Error", style=wx.ICON_HAND)
            err.ShowModal()
        else:
            self.txt.SetLabel(MainWindow.quote[0])
            self.txt.SetForegroundColour("BLUE")
            self.sizer.Layout()

    def on_clear_last(self, e):
        if MainWindow.quote_altered:
            self.txt.SetLabel("".join(MainWindow.split_buffer))
        else:
            self.txt.SetLabel("".join(MainWindow.base_copy))
        self.txt.SetForegroundColour("BLACK")
        self.sizer.Layout()


    def on_clear_all(self, e):
        print MainWindow.base_copy
        MainWindow.split_cryptoquote = MainWindow.base_copy
        MainWindow.split_buffer = MainWindow.base_copy
        MainWindow.quote_altered = False
        self.txt.SetLabel("".join(MainWindow.base_copy))
        self.txt.SetForegroundColour("BLACK")
        self.sizer.Layout()


app = wx.App(False)
frame = MainWindow(None, "Cryptogrammar")
frame.Show()
app.MainLoop()
  

Ответ №1:

(Тем не менее, я делаю вызов в on_clear_all, чтобы установить для split_cryptoquote значение base_copy, но это не должно изменять base_copy.)

Вы заметили свою собственную проблему:

MainWindow.split_cryptoquote = MainWindow.base_copy привязывается MainWindow.split_cryptoquote к тому же объекту, что и MainWindow.base_copy , поэтому, когда вы изменяете один, вы изменяете другой.

Если вы измените строку на

MainWindow.split_cryptoquote = MainWindow.base_copy[:]

Вы заставите python создать новый объект (копию MainWindow.base_copy ) , и эта проблема не должна возникать.

Редактировать: Строка ниже: MainWindow.split_buffer = MainWindow.base_copy я думаю, также нуждается в такой же обработке.

Смотрите этот пример:

 >>> lista = [1,2]
>>> listb = lista
>>> listb.append(3)
>>> lista
[1, 2, 3]
>>> listb
[1, 2, 3]

>>> listc = lista[:]
>>> listc.append(4)
>>> listc
[1, 2, 3, 4]
>>> lista
[1, 2, 3]