Writing a Python class that provides default instance succinctly I have a Python class for which I'm often going to want an instance with the default arguments, but I want the class to allow creation of instances. For brevity I'd prefer that the default instance be accessible as a property, so that it can be accessed without a method call. However, the code to achieve this in the way I know how is complicated (see below); it feels too complicated for such a simple task. The solution that suggests itself to me is to give up on using properties (in my context a multiton would even work), but I wonder: is there a better way?

# https://stackoverflow.com/a/1383402/2829764
class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()


class Example:
    _default_instance = None

    def __init__(self, customizable=0):
        self.customizable = customizable

    def get_default_instance(cls):
        if cls._default_instance is None:
            cls._default_instance = cls()
        return cls._default_instance
    def set_default_instance(cls):
        raise NotImplementedError("Can't do this")
    default_instance = ClassProperty(classmethod(get_default_instance), classmethod(set_default_instance))

    def do_something(self):
        print("*** {} ***".format(self.customizable*2))


foo = Example(10)
foo.do_something()

foo.default_instance.do_something()


Output:

*** 20 ***
*** 0 ***


NOTE: I don't care about default_instance being read-only; that was just a byproduct of the ClassProperty code I used from https://stackoverflow.com/a/1383402/2829764.
I'd say a much easier way to accomplish this is to use a module instead of a class.  In a language like Java the primary form of encapsulation is a class, while in Python, the primary form of encapsulation is a module.  For example,

foo.py

class Example:

    def __init__(self, customizable):
        self.customizable = customizable

    def do_something(self):
        print("*** {} ***".format(self.customizable*2))

default_instance = Example(0)


main.py

import foo

my_foo = foo.Example(20)
my_foo.do_something()

foo.default_instance.do_something()


Output:

*** 20 ***
*** 0 ***


If you really wanted the default instance to be a class level attribute of Example, then you could add this line to foo.py

Example.default_instance = Example(0)


Personally, I don't think making this read only adds that much value; in general we let people do what they want in Python (that's why we don't have language defined private/protected/internal/public/etc features).  If the user wants to mess with something they shouldn't, that's on them.