如何避免使用全局变量?

时间:2019-02-13 10:04:46

标签: python

中断20年后重新开始编程。一直在阅读的内容是,在python中使用全局变量是不良设计的标志,但无法找到一种更好的方法。

下面是一个小程序,它利用全局变量“ paused”来确定音乐播放器的状态。此变量由几个函数使用。

在不利用全局变量的情况下还有更好的方法吗?

# Global variable to access from multiple functions
paused = False


def play_music():

    global paused

    if not paused:

        try:
            mixer.music.load(filename)
            mixer.music.play()
            statusBar['text'] = 'Playing Music - ' + os.path.basename(filename)
        except:
            tkinter.messagebox.showerror('File not found',
                                         'Melody could not find the file.')
    else:
        mixer.music.unpause()
        paused = False
        statusBar['text'] = 'Playing Music - ' + os.path.basename(filename)


def stop_music():
    mixer.music.stop()
    statusBar['text'] = 'Music stopped'


def pause_music():

    global paused

    if not paused:
        mixer.music.pause()
        paused = True
        statusBar['text'] = 'Music paused'

    else:
        play_music()

4 个答案:

答案 0 :(得分:8)

您可以将所有函数放在一个类中,并将“全局”变量设置为属性。这样,您可以在方法之间共享它:

class Player(object):
    def __init__(self):
        self.paused = False
    def play_music(self):
        if not self.paused:
            # and so on
    def pause_music(self):
        if not self.paused:
            # etc.

答案 1 :(得分:1)

万一其他人感兴趣,下面是经过改进的代码,其中创建了一个Player类来封装暂停变量:

import os
from tkinter import *
from tkinter import filedialog
import tkinter.messagebox
from pygame import mixer

# Global variable to access from multiple functions
# paused = False


class Player:

    def __init__(self):
        self.paused = False
        self.filename = None

    def play_music(self):

        if not self.paused:

            try:
                mixer.music.load(self.filename)
                mixer.music.play()
                statusBar['text'] = 'Playing Music - ' + os.path.basename(self.filename)
            except FileNotFoundError:
                tkinter.messagebox.showerror('File not found',
                                             'Melody could not find the file. Please choose a music file to play')
        else:
            mixer.music.unpause()
            self.paused = False
            statusBar['text'] = 'Playing Music - ' + os.path.basename(self.filename)

    @staticmethod
    def stop_music():
        mixer.music.stop()
        statusBar['text'] = 'Music stopped'

    def pause_music(self):

        if not self.paused:
            mixer.music.pause()
            self.paused = True
            statusBar['text'] = 'Music paused'

        else:
            self.play_music()

    def rewind_music(self):
        self.play_music()
        statusBar['text'] = 'Music rewound'

    @staticmethod
    def set_volume(val):
        # val is set automatically by the any tkinter widget

        volume = int(val)/100   # mixer only takes value between 0 and 1
        mixer.music.set_volume(volume)

    # Create about us Message Box
    @staticmethod
    def about_us():

        tkinter.messagebox.showinfo('About Melody', 'This is a music player built using python and tkinter')

    def browse_file(self):

        self.filename = filedialog.askopenfilename()
        print(self.filename)


# Create main window
root = Tk()

# Create window frames
middle_frame = Frame(root)
bottom_frame = Frame(root)

# Create Menu
menu_bar = Menu(root)
root.config(menu=menu_bar)

# Create Player object
player = Player()

subMenu = Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="File", menu=subMenu)
subMenu.add_command(label="Open", command=player.browse_file)
subMenu.add_command(label="Exit",  command=root.destroy)

# it appears we can re-use subMenu variable and re-assign it
subMenu = Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="Help", menu=subMenu)
subMenu.add_command(label="About Us", command=player.about_us)


# Initialise Mixer
mixer.init()

# Create and set the main window
root.title("Melody")
root.wm_iconbitmap(r'favicon.ico')
# root.geometry('300x300')


# Create and arrange widgets
text = Label(root, text="Lets make some noise!")
text.pack(pady=10)
middle_frame.pack(pady=30, padx=30)   # Place the middle and bottom frame below this text
bottom_frame.pack()

playPhoto = PhotoImage(file='play-button.png')
playBtn = Button(middle_frame, image=playPhoto, command=player.play_music)
playBtn.grid(row=0, column=0, padx=10)

stopPhoto = PhotoImage(file='stop-button.png')
stopBtn = Button(middle_frame, image=stopPhoto, command=player.stop_music)
stopBtn.grid(row=0, column=1, padx=10)

pausePhoto = PhotoImage(file='pause-button.png')
pauseBtn = Button(middle_frame, image=pausePhoto, command=player.pause_music)
pauseBtn.grid(row=0, column=2, padx=10)

rewindPhoto = PhotoImage(file='rewind-button.png')
rewindBtn = Button(bottom_frame, image=rewindPhoto, command=player.rewind_music)
rewindBtn.grid(row=0, column=0, padx=20)

# Create and set volume slider
scale = Scale(bottom_frame, from_=0, to=100, orient=HORIZONTAL, command=player.set_volume)
scale.set(70)  # set default slider and and volume
player.set_volume(70)
scale.grid(row=0, column=1, padx=10)

statusBar = Label(root, text='Welcome to Melody', relief=SUNKEN, anchor=W)
statusBar.pack(side=BOTTOM, fill=X)

# Keep main window displayed
root.mainloop()

答案 2 :(得分:0)

实际上,不建议使用全局变量。您可能会有副作用,导致程序出现意外行为。

上面有可能(使用类),但是另一种解决方案是将变量作为函数的参数传递。

def play_music(paused):
  ...
def stop_music(paused):
  ...
def pause_music(paused):
  ...

答案 3 :(得分:0)

如果您不想使用类,则可以传递一个带有暂停键的设置字典,该字典将在您的所有函数中发生变化

def play_music(settings):
    # some extra code
    settings['pause'] = False

def stop_music(settings)
    # some extra code
    settings['pause'] = None

def pause_music(settings):
   # some extra code
   settings['pause'] = True

def main():
    settings = {'pause': None}
    play_music(settings)
    .....