1

In Python, what’s the best practice for creating multiple objects from the same class? For example:

(doc, grumpy, happy, sleepy, bashful, sneezy, dopey) = Dwarf(), Dwarf(), Dwarf(), Dwarf(), Dwarf(), Dwarf(), Dwarf()

This is pretty unwieldy. A generator expression can shorten it:

(doc, grumpy, happy, sleepy, bashful, sneezy, dopey) = (Dwarf() for i in range(7))

The for i in range(7) bit seems like it ought to be unnecessary though. I've seen a suggestion of using ... = (object,)*7, but that only works for immutable basic types (numbers, strings, tuples, etc.). If used for user classes, it will assign all names to the same object.

I'm mostly asking out of curiosity, though I do sometimes need this for test code. I've searched fairly extensively and haven't found a definitive answer.

Community
  • 1
  • 1
duozmo
  • 1,698
  • 5
  • 22
  • 33

2 Answers2

2

If you need many similar variables, you can use a dict instead of spamming global namespace with new variables. Try this:

dwarf_names = "doc grumpy happy sleepy ...".split():
dwarfs = {name: Dwarf() for name in dwarf_names}

And use them like dwarfs["grumpy"].call_the_prince() instead of grumpy.call_the_prince().

And if creating new variables is a must (I don't think they should tho):

locals().update(dwarfs)

shold do the trick, but it's pretty ugly for this simple question.

Note: On older Python versions where dict comprehensions doesn't exist:

dwarfs = dict((name, Dwarf()) for name in dwarf_names)
utdemir
  • 26,532
  • 10
  • 62
  • 81
  • 1
    Seriously *don't* use `locals().update` unless you *really*, *really* know what you're doing. It can go wrong in so many ways. Further, there are normally far better solutions (eg. `namedtuple`s). The `dict` comprehension is a good idea, though. – Veedrac Jun 08 '14 at 15:42
2

It seems a little strange the dwarves don't know their own names, but:

make_dwarf = lambda *x: Dwarf()

doc, grumpy, happy, sleepy, bashful, sneezy, dopey = map(make_dwarf, xrange(7))

You could also use one of these approaches:

def multiple(callable, count):
    return (callable() for _ in xrange(count))

doc, grumpy, happy, sleepy, bashful, sneezy, dopey = multiple(Dwarf, 7)

or

def multiple(Type):
    return type('Muliplier', (object,),
        {'__mul__': lambda self, count: (Type() for _ in xrange(count))})()

doc, grumpy, happy, sleepy, bashful, sneezy, dopey = multiple(Dwarf) * 7

These latter two may seem like a lot of typing, but they're generic in the sense that they would work with any type that can be called with no arguments — and could be modified to handle those that do, too.

martineau
  • 119,623
  • 25
  • 170
  • 301