0

Let's say I have a dictionary of dogs, where the key is the name of the dog and the value is an instance of a class Dog.

my_dogs = {'Ollie': Dog(...), 'Lassie': Dog(...)}

If I want to know my dogs I can access them by key

my_dogs['Ollie']

I would like however to have this structure as a class, something like

class MyDogs():
    def __init__(self):
        self.ollie = Dog()
        self.lassie = Dog()

So I can access my dogs like:

my_dogs = MyDogs()
my_dogs.lassie   

Using a dictionary I can create any names for my dogs by just setting the key to it's name, however in the class the variable is hardcoded, which is something that I don't want.

Question: Can I define a variable whose name is stored in another variable? Something like:

class MyDogs():
    def __init__(self, dog_names):
        self.eval(dog_names[0]) = Dog()
        self.eval(dog_names[1]) = Dog()

This way MyDogs will have two instances named after the dog_names passed as parameters.

Is this possible? Is it a good practice or I should structure it differently?

  • 3
    Why do you want a class when a dict suffice? – 9769953 Jul 24 '19 at 15:02
  • 1
    You can use `getattr`, but with your example given, you should stick to using a dict. – 9769953 Jul 24 '19 at 15:03
  • 2
    It is not good practice. There's no need for a class here. – chepner Jul 24 '19 at 15:04
  • Is there any reason you want to specifically access the dogs as attributes instead of names? It actually seems very limiting the alternative of a class. I mean, where is the dynamic here? You set an attribute of `lassie` and that's it... it's there as `lassie` – Tomerikoo Jul 24 '19 at 15:05
  • This is a toy example, but imagine a situation where I want a class to have methods whose name might come from a configuration file. So you don't want to hardcode their names. Like a device with two ports which might be called differently depending on the Configuration used. –  Jul 24 '19 at 15:05
  • 1
    Even in that case you are describing it won't be necessary as you still can't do `my_class.function()` as the function here will be a name – Tomerikoo Jul 24 '19 at 15:07
  • Than you should show a toy model where this makes more sense. Still, it may be better to use a `dict` as a class attribute, and use that: `name = 'Lassie'; my_dogs.names[name]`. – 9769953 Jul 24 '19 at 15:07

2 Answers2

1

You can use setattr for this

class MyDogs():
    def __init__(self, dog_names):
        for dog_name in dog_names:
          setattr(self, dog_name, Dog())
0

Maybe overkill but you could implement a class that mimics a dictionary using MutableMapping, this way you could have the interface you suggest:

from collections.abc import MutableMapping


class Dog:

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

    def __repr__(self):
        return str(self.name)


class MyDogs(MutableMapping):

    def __init__(self, dog_names):
        for name in dog_names:
            self[name] = Dog(name)

    def __getitem__(self, key):
        return self.__dict__[key]

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, key):
        del self.__dict__[key]

    def __iter__(self):
        return iter(self.__dict__)

    def __len__(self):
        return len(self.__dict__)


my_dogs = MyDogs(['lassie', 'ollie'])
print(my_dogs.lassie)
print(my_dogs.ollie)

out:

'lassie'
'ollie'
Oliver Scott
  • 1,673
  • 8
  • 17