Variable scope outside of classes

22,392

Solution 1

Yep, that's exactly how global works.

It seems to me you are doing it right, as it's done this way in some modules of the python standard library (fileinput, for example).

Solution 2

In this code:

global ftp_client # does it reference the variable of the outer scope?
self.ftp_client = ftplib.FTP('foo')

you declare ftp_client as a global variable. This means it lives at the module level (where your classes are for example).

The second line is wrong. You wanted to assign to the global variable but instead you set an instance attribute of the same name.

It should be:

global ftp_client
ftp_client = ftplib.FTP('foo')

But let me suggest a different approach. A common practice is to put such stuff inside the class, since it is shared by all instances of this class.

class FtpFileCommand(sublime_plugin.TextCommand):
  ftp_client = None

  def run(self, args):
    FtpFileCommand.ftp_client = ftplib.FTP('foo')
    # login and stuff

Notice that the method doesn't use self so it might as well be a class method:

class FtpFileCommand(sublime_plugin.TextCommand):
  ftp_client = None

  @classmethod
  def run(cls, args):
    cls.ftp_client = ftplib.FTP('foo')
    # login and stuff

This way you will get the class as the first argument and you can use it to access the FTP client without using the class name.

Solution 3

If there's only a single shared variable, then a global is the simplest solution. But note that a variable only needs to be declared with global when it is being assigned to. If the global variable is an object, you can call its methods, modify its attributes, etc without declaring it as global first.

An alternative to using global variables is to use class attributes which are accessed using classmethods. For example:

class FtpFile(object):
    _client = None

    @classmethod
    def client(cls):
        return cls._client

    @classmethod
    def setClient(cls, client):
        cls._client = client

class FtpFileCommand(FtpFile, sublime_plugin.TextCommand):
    def run(self, args):
        client = self.client()

class FtpFileEventListener(FtpFile, sublime_plugin.EventListener):
    def run(self, args):
        client = self.client()
Share:
22,392
fjdumont
Author by

fjdumont

Updated on October 07, 2020

Comments

  • fjdumont
    fjdumont over 3 years

    My text editor of choice is extensible through python plugins. It requires me to extend classes and override its methods. The general structure looks similar the snippet below. Note that the function signature is fixed.

    ftp_client is supposed to be shared by instances of both classes.

    ftp_client = None
    
    class FtpFileCommand(sublime_plugin.TextCommand):
      def run(self, args):
        global ftp_client # does it reference the variable of the outer scope?
        self.ftp_client = ftplib.FTP('foo')
        # login and stuff
    
    class FtpFileEventListener(sublime_plugin.EventListener):
      def run(self, args):
        global ftp_client # same for this
        self.ftp_client.quit() # 
    

    Both of these classes are supposed to have one variable in common. What is the best practice in order to share variables?

    Edit based on madjars answer:

    FtpFileCommand.run is called first, instanciates ftp_client and works like a charm. FtpFileEventListener.run is called later and, can reference ftp_client perfectly but it is still None. Using the global keyword, does it add the variable as a member to self?

  • Xavier Combelle
    Xavier Combelle over 12 years
    I'm afraid that the plugin system may not accept pzarameters to plugins
  • fjdumont
    fjdumont over 12 years
    Xavier Combelle: exactly, the structure given in my post is fixed and I am not allowed to override the constructors.
  • fjdumont
    fjdumont over 12 years
    I edited the question based on your answer, please have a look :)
  • madjar
    madjar over 12 years
    After doing global ftp_client, you can access it using ftp_client. Be careful, because self.ftp_client will refer to the attribute of the instance, which is different of the global ftp_client.
  • fjdumont
    fjdumont over 12 years
    Thanks for answering that quickly. Honestly, reasearching the docs could've helped me as well. Lazy me...
  • fjdumont
    fjdumont over 12 years
    Now that's a smart solution! Thanks for clarifying that global is only required during assignment. I just +1'd your answer because I feel naughty removing the solution mark from madjars answer...