0

I'm trying to have a default instance of a class. I want to have

class Foo():
    def __init__(self):
        ....

    _default = Foo()

    @staticmethod
    def get_default():
        return _default

However _default = Foo() leads to NameError: name 'Foo' is not defined

3
  • Note that __init is not a special method; it's __init__. Commented Nov 4, 2013 at 23:01
  • 2
    Meanwhile, this smells like an XY problem. Many people who want to do this, but have no idea how, are trying to write Java-style code in Python, when there's actually a much better way to solve their real problem. So, why do you want a "default instance" that you get with a staticmethod like this? Why not, e.g., just have a global default_foo object? (Yes, globals are bad—but singletons are globals, they just hide their globalness in a way that solves none of the problems but makes things more complicated). Commented Nov 4, 2013 at 23:03
  • For that matter, even if you do want the global default instance to be owned by the class, why do you want a getter method for it? That's almost always a sign of a non-pythonic design. Commented Nov 4, 2013 at 23:05

3 Answers 3

5

Foo does not exist until the class definition is finalized. You can easily refer to it after the class definition, though:

class Foo(object):
    def __init__(self):
    # ....

Foo.default_instance = Foo()

Note also that I have removed the superfluous getter method in favor of a plain old attribute.

You can also solve the problem with a decorator:

def defaultinstance(Class):
    Class.default_instance = Class()
    return Class

@defaultinstance
class Foo(object):
    # ...

Or, gratuitously, with a metaclass:

def defaultmeta(name, bases, attrs):
    Class = type(name, bases, attrs)
    Class.default_instance = Class()
    return Class

# Python 2.x usage
class Foo(object):
    __metaclass__ = defaultmeta
    # ...

# Python 3.x usage
class Foo(metaclass=defaultmeta):
    # ...

When might you might want to use each method?

  • Use the post-definition class attribute assignment for one-offs
  • Use the decorator if you want the same behavior in a lot of unrelated classes and to "hide" the implementation of it (it's not really hidden, or even that complicated, here, though)
  • Use the metaclass if you want the behavior to be inheritable in which case it's not really gratuitous. :-)
Sign up to request clarification or add additional context in comments.

4 Comments

I think you want to delete the _default = Foo() line in the middle there.
Calling Foo.get_default() will raise a NameError for _default.
Yeah, I foolishly cut and pasted the OP's original code there.
+1 for gratuitous metaclass answer! but seriously, the first one is the way I would go.
2

You cannot refer to a class that doesn't yet exist. Within the class definition body, the Foo class is not yet created.

Add the attribute after the class has been created:

class Foo():
    def __init__(self):
        ....

    @staticmethod
    def get_default():
        return Foo._default


Foo._default = Foo()

Note that you also need to alter the get_default() static method; the class body doesn't form a scope, so you cannot reach _default as a non-local from get_default().

You are now, however, repeating yourself a lot. Reduce repetition a little by making get_default() a classmethod instead:

class Foo():
    def __init__(self):
        ....

    @classmethod
    def get_default(cls):
        return cls._default


Foo._default = Foo()

or create the default on first call:

class Foo():
    def __init__(self):
        ....

    @classmethod
    def get_default(cls):
        if not hasattr(cls, '_default'):
            cls._default = cls()
        return cls._default

Comments

0

You may lazily initialize your default instance.

class Foo(object):

    _default = None

    @staticmethod
    def get_default():
        if not Foo._default:
            Foo._default = Foo()
        return Foo._default

1 Comment

trying to avoid the lazy initialization since its not thread safe

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.