如何避免使用全局变量?(python-flask socketio应用程序)

如何避免使用全局变量?(python-flask socketio应用程序),python,global-variables,flask-socketio,Python,Global Variables,Flask Socketio,我试图找出如何在我的应用程序中不使用全局变量,但我想不出其他任何东西 我实际上是在Flask SocketIO模块的帮助下编写一个web界面,以便与音乐播放器实时交互 这是包含play函数的代码片段(我想我只需要一个示例,然后我就可以将其用于所有其他函数): 这只是一个精简版本的代码,但我认为它足以理解我试图实现的目标 我还需要从其他函数访问该变量,我需要对歌曲名称、持续时间和当前时间执行相同的操作 提前感谢您的帮助,如果我的英语不清楚,请原谅 以下是我使用的解决方案: from flask

我试图找出如何在我的应用程序中不使用全局变量,但我想不出其他任何东西

我实际上是在Flask SocketIO模块的帮助下编写一个web界面,以便与音乐播放器实时交互

这是包含play函数的代码片段(我想我只需要一个示例,然后我就可以将其用于所有其他函数):

这只是一个精简版本的代码,但我认为它足以理解我试图实现的目标

我还需要从其他函数访问该变量,我需要对歌曲名称、持续时间和当前时间执行相同的操作

提前感谢您的帮助,如果我的英语不清楚,请原谅


以下是我使用的解决方案:

from flask import Flask, render_template
from flask_socketio import SocketIO

app = Flask(__name__)
socketio = SocketIO(app)

class Player():
    def __init__(self):
        self.isPlaying = False


    def cycle_play(self):
        if self.isPlaying == True:
            socketio.emit('pause', broadcast=True)
            self.isPlaying = False
        else:
            socketio.emit('play', broadcast=True)
            self.isPlaying = True


if __name__ == '__main__':
    player = Player()
    socketio.on('request_play')(player.cycle_play) #this is the decorator
    socketio.run(app, port=5001)

建议自己的解决方案是定义一个类,该类封装状态变量和对其更改的响应。由于我不熟悉Flask SocketIO的详细信息,请将其视为psedoocode,而不是要粘贴到工作程序中的内容

class PlayControl:
    def __init__(self, initial):
        self.is_playing = initial
    def cycle_play(self):
        if self.is_playing:
            socketio.emit('pause', broadcast=True)
            self.is_playing = False
    else:
            socketio.emit('play', broadcast=True)
            self.is_playing = True
然后,您将创建该类的一个实例,并将该实例的
cycle\u play
方法传递给您装饰原始函数的同一个函数。因为这种行为是动态的,所以不适合在方法定义上使用decorator

control = PlayControl(False)
socketio.on('request_play')(control.cycle_play)

为了减少程序代码的数量,您甚至可以定义一个类,将要调用的函数和要发出的值作为参数,进一步概括这个概念,使代码更简洁,使用更少的样板文件。

我的建议是使用一个类,在init方法中只使用self.isplay=False。您始终可以从类中的所有函数中引用此变量。 例如:

class PLAYER(object):   
   def __init__(self,other parameters):
    self.isPlaying = False
    #your cod
   def cycle_play(self):
        #global isPlaying
        if self.isPlaying == True:
           socketio.emit('pause', broadcast=True)
           self.isPlaying = False
        else:
           socketio.emit('play', broadcast=True)
           self.isPlaying = True

您可以使用用户会话来存储这些值。您可以在此处阅读有关会话对象的更多信息:flask.pocoo.org/docs/0.12/quickstart/#sessions

from flask import session

@socketio.on('initialize')
def initialize(isPlaying):
    session['isPlaying'] = isPlaying

@socketio.on('request_play')
def cycle_play():
    # Note, it's good practice to use 'is' instead of '==' when comparing against builtin constants.
    # PEP8 recommended way is to check for trueness rather than the value True, so you'd want to first assert that this variable can only be Boolean.
    assert type(session['isPlaying']) is bool

    if session['isPlaying']: 
        socketio.emit('pause', broadcast=True)
        session['isPlaying'] = False
    else:
        socketio.emit('play', broadcast=True)
        session['isPlaying'] = True

您对全局变量的关注点是什么?如果必须从其他函数访问变量,那么它必须位于主环境中。如果不希望函数直接与之交互,可以将“def cycle_play(copy_of_global_variable)”放在函数的开头,将“return(copy_of_global_variable)”放在函数的结尾,然后必须记住使用“global_variable=cycle_play(global_variable)”调用函数.@F.Rossi我没有使用Flask+socketio的经验,但在web应用程序中使用进程全局状态通常是一个很大的禁忌。要么是每个用户的状态,您希望通过会话对其进行管理,要么是“共享”状态,您希望通过一些数据库(关系型或非关系型)对其进行管理。感谢您提供有关使用“is”的信息,然而,也许我遗漏了一些东西,但会话是某个东西的标准名称吗?因为我得到了这个错误:NameError:name'session'没有定义“#注意,在与内置常量进行比较时,最好使用'is'而不是'==''”=>Nope,在这种情况下最好的做法是不与任何东西进行比较,所有python对象在布尔上下文中使用时都有一个真值,所以
如果有什么:dou this()
是这里的好做法。当您想要比较对象标识(两个名称都指向同一个对象)时,您只能使用
is
。也就是说,如果必须维护的状态是“每用户”状态,那么使用会话确实非常有意义@F.Rossi您需要导入
会话
才能使用它:
如果某件事是真的
如果某件事==True
一样糟糕,这是一个常见的错误。如果有什么东西,只需使用
。如果您确实需要一个布尔值,您可以始终使用
bool(something)
。[从肥皂盒中下来]。添加缺少的导入可能会有帮助。我对此进行了改进,因为它使用了知识,我不必提供比我可能仓促接受的答案更好的解决方案。如果提问者读到:您可能会重新考虑您的选择(我相信您可以更改您接受的答案0。我没有使用Flask+socketio的经验,但我怀疑在任何web应用程序中使用流程全局状态(上例中的
控件
对象仍然是全局的)。正确。但您可以(例如)有一个控件列表,或者一个你可以按名称查找的控件字典。但是,你已经知道了。也许我对OP的具体需求的回答过于狭隘。如果我没有犯错误的格式错误(现已修复),这可能会有所帮助。“也许我对OP的具体需求的回答过于严格。”:是的,我的拙见…当你有多个单一进程为应用服务时,即使是列表或目录等也会崩溃(多进程设置是标准)。这就是为什么我们使用数据库(任何类型)用于状态持久性和进程间共享。谢谢。我读得不够仔细,应该已经回答了关于会话状态的问题。对于任何Python主题,您都不必谦虚。这很好,但您仍然需要安排所需的事件来在该类的特定实例上调用该方法。
from flask import session

@socketio.on('initialize')
def initialize(isPlaying):
    session['isPlaying'] = isPlaying

@socketio.on('request_play')
def cycle_play():
    # Note, it's good practice to use 'is' instead of '==' when comparing against builtin constants.
    # PEP8 recommended way is to check for trueness rather than the value True, so you'd want to first assert that this variable can only be Boolean.
    assert type(session['isPlaying']) is bool

    if session['isPlaying']: 
        socketio.emit('pause', broadcast=True)
        session['isPlaying'] = False
    else:
        socketio.emit('play', broadcast=True)
        session['isPlaying'] = True