3

I am trying to learn design patterns in Python. The recommended approach for implementing global variables is through the Borg pattern.

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state

This seems to be a dictionary. How would I store more complicated data structures, say a Pandas dataframe or a custom class, to be used by globally?

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
Richard Foo
  • 185
  • 3
  • 6

2 Answers2

6

Actually, this is not the recommended approach, and I have never seen it used in real code.

The recommended approach is to use a module as a module already has a "global" namespace (see this answer for more info on globals(), locals(), and vars()).


However, in the interests of understanding:

What you have so far is only a basic framework for shared state at the instance level. What you need now is the rest of the state you want to track:

class Config(Borg):

    def __init__(self, config_file):
        super(Config, self).__init__()
        # load and parse file, saving settings to `self`

One disadvantage to this method is that you can have several instances consuming memory that all know the same thing. (Not much memory, true.)

Another method of accomplishing "shared state" is to only create one instance, and then have the class always return that same instance -- otherwise known as a singleton.

class Config(object):

    the_one = None

    def __new__(cls, config):
        if cls.the_one is None:
            cls.the_one = Super(Config, cls).__new__(cls)
            # load and parse file, saving settings to `cls.the_one`
        return cls.the_one

Either method would result in the following:

>>> config = Config('my_config_file.cfg')
>>> config.screen_size
# whatever was saved during the loading and parsing of the config file
# for 'screen_size'
Community
  • 1
  • 1
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
6

This is not recommended:

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state # ***

There is absolutely no need for different objects with the same __dict__. Here you make every instance hold precisely the same data. You may as well make the object a singleton and avoid creating redundant objects:

class Borg(object):
    instance = None
    def __new__(cls):
        if cls.instance is None:
            cls.instance = super(Borg, cls).__new__(cls)
        return cls.instance

>>> b1 = Borg()
>>> b2 = Borg()
>>> b1 is b2
True

But why even do that? Modules are essentially singletons with a namespace where you can store data and functionality.

I would just use a module.

How would I store more complicated data structures, say a Pandas dataframe or a custom class, to be used by globally?

Simple - store your data in the globals of a module (e.g. module.py), like this:

global_dataframe = pandas.DataFrame()

class CustomClass:
    """my Python class definition"""

global_dataframe and CustomClass are both now module level globals. You can import the module they are in, and reference them by dotted lookup.

>>> import module
>>> module.global_dataframe
Empty DataFrame
Columns: []
Index: []
>>> module.CustomClass
<class module.CustomClass at 0x7fdf73f3d0b8>
Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331