简体   繁体   English

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

[英]How can I avoid to use global variables? (python - flask-socketio app)

I'm trying to figure out how to not use global variables for my application but I can't think of anything else. 我试图弄清楚如何不在我的应用程序中使用全局变量,但是我什么也没想到。

I'm actually coding a web interface with the help of the Flask-SocketIO module to interact in real time with a music player. 我实际上是在Flask-SocketIO模块的帮助下对Web界面进行编码,以与音乐播放器进行实时交互。

This is a snippet of my code containing the play function (I think I only need one example and then I can adapt it for all the other functions): 这是我的包含播放功能的代码的片段(我想我只需要一个示例,然后就可以将其适应所有其他功能):

from flask import Flask, render_template
from flask_socketio import SocketIO

app = Flask(__name__)
socketio = SocketIO(app)
isPlaying = False #This is the variable that I would like to avoid making global

@socketio.on('request_play')
def cycle_play():
    global isPlaying
    if isPlaying == True:
        socketio.emit('pause', broadcast=True)
        isPlaying = False
    else:
        socketio.emit('play', broadcast=True)
        isPlaying = True

if __name__ == '__main__':
    socketio.run(app, port=5001)

This is only a stripped down version of the code but I think it's enough to understand what I'm trying to accomplish. 这只是代码的简化版本,但我认为足以理解我要完成的工作。

I need to access that variable also from other functions and I need to do the same with the song name, duration and current time. 我还需要从其他函数访问该变量,并且需要对歌曲名称,持续时间和当前时间进行相同的操作。

Thanks in advance for the help and sorry if my English is not clear. 在此先感谢您的帮助,如果我的英语不太清楚,请多谢。


Here is the solution that I used: 这是我使用的解决方案:

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)

You can use the user session to store such values. 您可以使用用户会话来存储此类值。 You can read up more about the session object here: flask.pocoo.org/docs/0.12/quickstart/#sessions. 您可以在此处阅读有关会话对象的更多信息: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

The solution that suggests itself is to define a class which encapsulates both the state variable and the responses to its change. 建议自己的解决方案是定义一个类,该类既封装状态变量又包含对其变化的响应。 Since I'm not familiar with the details of Flask-SocketIO please treat this as pseduocode rather than something to be pasted in to a working program. 由于我不熟悉Flask-SocketIO的详细信息,因此请将此视为pseduocode,而不是将其粘贴到工作程序中。

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

You would then create an instance of this class, and pass the instance's cycle_play method to the same function you decorated your original function with. 然后,您将创建此类的实例,并将该实例的cycle_play方法传递cycle_play装饰原始函数相同的函数。 Because this behaviour is dynamic it's not appropriate to use a decorator on the method definition. 由于此行为是动态的,因此不适合在方法定义上使用装饰器。

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

To reduce the amount of program code you could even define a class that took the functions to call and the values to emit as arguments, generalising the concept further to make code more concise and with less boilerplate. 为了减少程序代码的数量,您甚至可以定义一个以调用函数作为参数并将值作为参数发出的类,进一步推广该概念,以使代码更简洁,更少样板。

My advice would be use a class and inside init method just use self.isPlaying = False. 我的建议是使用类,并且在init方法内部仅使用self.isPlaying = False。 You can always refer to this variable from all the function in the class. 您始终可以从类中的所有函数中引用此变量。 for exemple: 举个例子:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM