mingxiao
mingxiao

Reputation: 1812

create instance of class within class definition

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

Upvotes: 0

Views: 355

Answers (3)

kindall
kindall

Reputation: 184455

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. :-)

Upvotes: 5

Giulio Piancastelli
Giulio Piancastelli

Reputation: 15817

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

Upvotes: 0

Martijn Pieters
Martijn Pieters

Reputation: 1125048

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

Upvotes: 2

Related Questions