2
\$\begingroup\$

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.

\$\endgroup\$

migrated from programmers.stackexchange.com Aug 4 '15 at 2:52

This question came from our site for professionals, academics, and students working within the systems development life cycle.

  • \$\begingroup\$ So... You want a pseudo singleton? \$\endgroup\$ – Dannnno Aug 4 '15 at 13:57
  • \$\begingroup\$ @Dannnno, that's right, I want a pseudo-singleton. \$\endgroup\$ – kuzzooroo Aug 4 '15 at 13:59
6
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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