4

I'm working on a Python application in which there are two Singleton classes: App and Configuration.

The former seems straight forward, only ever instantiate one App instance; the latter seems controversial.

From the searches I've done, I need Configuration to be accessible from other modules that update the application's configuration file (and subsequently update the application). To do this, I've designed my class as a Singleton by controlling instantiation through its metaclasses __call__ method. To access the instance, in any module I do the following:

from app.config import Configuration

class Foo:

    def __init__(self, *args, **kwargs):
        self.config = Configuration()

Now, Foo is some feature beloning to App, I could've just as easily done:

from app import App

class Foo:

    def __init__(self, *args, **kwargs):
        self.config = App().configuration

Where App() returns the application Singleton and .configuration was an attribute where the Configuration was first instantiated. Further searching shows I could even use the app.config module as a Singleton, since Python only loads modules once. So regardless of defining a class as a Singleton or treating the module as a Singleton, the Singleton Pattern remains.

So what's wrong with either of these:

  1. Using the class Singleton
  2. Treating the module as a Singleton

In any case, I need a single configuration for the entire application. Creating multiple instances would lead to potential race conditions, so this seems like a smart way to handle it. Further, it seems extensible for features such as logging, right?

2
  • 7
    Does this answer your question? So Singletons are bad, then what?
    – gnat
    Commented May 4, 2020 at 20:17
  • You still have a singleton in both cases. You seem to be saying that singletons aren't bad because the alternative is different singletons? This is wrong; the alternative is not different singletons. Commented Jul 7, 2020 at 11:43

2 Answers 2

7

There is a frequent confusion between having only one and must absolutely have only one.

While the latter certainly requires a singleton, the former only requires some discipline to create a configuration object and inject it where it is used.

If you think that your configuration object must absolutely exist only once, it might probably be because you use a global configuration. While such a shortcut has some convenience, it creates a heavy hidden dependency that is not necessarily desirable.

10
  • 2
    @pstatix Couldn’t you imagine having several instances of your configuration? For example adopting a multi-tenant tenant architecture where every tenant wound use another configuration. My main argument here is not to prescribe the way to manage your configuration, but to challenge making it a singleton. In other words, if you need one instance of your config, just create one instance. If it is a global, and there’s no better alternative, tant pis. The singleton enforces unicity, so it should be used only if unicity is vital.
    – Christophe
    Commented May 4, 2020 at 21:29
  • 2
    @pstatix using a singleton instead of a global doesn’t make your design better: it’s clever but it just hides the dependency to a global state, and will make refactoring more difficult if one day you decide to break your config in smaller pieces and inject those where needed. In other words, if misused, the singleton transfers at class level (so to the general concept) a need which in reality about object instances (so a specific need). And this is not consistent with a sound separation of concerns. Unfortunately, singletons are often misused and hence their bad reputation.
    – Christophe
    Commented May 4, 2020 at 21:37
  • 1
    @pstatix Usually the recommended way is to create the configuration object once in your "root" class and pass it around via constructors (see stackoverflow.com/questions/130794/what-is-dependency-injection). That way you can substitute it easily in any class for testing purposes.
    – Ilmo Euro
    Commented May 5, 2020 at 10:11
  • 1
    @pstatix A singleton is a global. You get it through some global name
    – Caleth
    Commented May 5, 2020 at 11:10
  • 1
    To make an object only once without a singleton one simply needs to create it once in a method that is called only once. Main usually works for this. Once created it can be passed where needed. A singleton's only advantage is that you can call it from methods that are called more than once. It adds no extra safety from bad programmers. Bad programmers will construct it twice in main and they'll write a singleton with the if commented out. Commented Jul 6, 2020 at 23:30
3

In any case, I need a single configuration for the entire application.

You can use an external configuration file. You can instantiate multiple configuration objects, which may all simply read from and write to this very file. Therefore, you can obviously have multiple instances but a single set of configuration-related settings.

Creating multiple instances would lead to potential race conditions, so this seems like a smart way to handle it.

Singleton does not make any difference with respect to race conditions. You can access the same member of a singleton object from two threads as well. The object is the same, so you also have a race condition. Maybe you are confusing thread-safety with respect to initialization versus usage. You can make a Singleton thread-safe w.r.t. initialization in multiple colorful ways but this does not mean that this single-instance is also thread-safe to use.

Further, it seems extensible for features such as logging, right?

It is, indeed, but you will have a very hard time providing more than one logging implementation at a time, e.g. for separate parts of your application, because you cannot abstract a singleton anymore than that. You will have to expose everything through your singleton and things will get complicated fairly quickly.

So what's wrong with either of these:

  1. Using the class Singleton
  2. Treating the module as a Singleton

You cannot entirely infer the use of your classes just by looking at their public programming "interface" (API), i.e. you have hidden dependencies. A properly implemented singleton allows your classes to lie about their dependencies. Accessing the singleton from just about anywhere means you have to scan the source code meticulously if you are to find out what you are storing where. This makes your code a lot more fragile.

Then, when you suddenly decide that you need another configuration, changing the implementation of a Singleton comes at an overprice. You have to change all of your classes where you have used the singleton to employ a different implementation.

My personal suggestion in terms of architecture would be to avoid the Singleton or, at least, if you use app.config, hide it behind multiple classes, each of which exposes the very specific subset of the configuration settings that the expected consuming classes are going to use. You probably don't need access to the entire configuration in each and every consuming class, do you...?

1
  • Disagree with the first paragraph. If you have an object which wraps the configuration, you should create one object and reuse it. However... it should be reused by passing the same object around, not by just assuming it's always the same object! That way, one day when you want two of them, it will be easier to fix. Commented Jul 7, 2020 at 11:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.