flamenco
flamenco

Reputation: 2840

Initialize an object built from a class with a specific dictionary

The goal is to build a class with an __init__ method that will allow to create objects which will be initialized with a specific dictionary.

Details:

A file mydicts.py is a collection of various dictionaries. The object built from the class that I intent to create will be initialized to one of the dictionaries from mydicts.py.

mydicts.py example:

dict1 = {k1:v1, k2:v2,...,kn:vn}
dict2 = {k1:v1, k2:v2,...,km:vm}
etc.

My attempts:

class Example(dict):
    def __init__(self, dictx):
        self.dictx = getattr(__import__("mydicts", fromlist=['m']), dictx)

Results:

e = Example('dict1')
print e
{}        # <- got empty dictionary. Want {k1:v1, k2:v2,...,kn:vn}

The goal is to create objects such that:

a = Example(dict1)
print a
# {k1:v1, k2:v2,...,kn:vn}

b = Example(dict2)
print b
# {k1:v1, k2:v2,...,km:vm}

Upvotes: 1

Views: 700

Answers (2)

msw
msw

Reputation: 43487

I think you are making this far more complicated than it need be. Noting the manual says:

Direct use of __import__() is rare, except in cases where you want to import a module whose name is only known at runtime.

But you do know the module name at loading time, your data definition just has too many variable names. Much clearer would be my_dicts.py:

my_dicts = [
    {k1:v1, k2:v2,...,kn:vn},
    {k1:v1, k2:v2,...,km:vm},
    …
]

and example.py:

import my_dicts

class Example(dict):
    def __init__(self, n):
        """Returns an Example instance loaded with the nth element
           of my_dict."""
        super(Example, self).__init__(my_dicts.my_dicts[n])

Upvotes: 1

user2555451
user2555451

Reputation:

Since you did not define a custom __str__ method for your class, print is calling the __str__ method of the parent class dict. Moreover, this is causing Python to print the empty dictionary created by the parent class in dict.__new__ instead of the dictionary that you have stored in self.dictx.

Because your class inherits from dict, you should be passing the dictionary returned by getattr to the __init__ method of the parent class. You can use super for this:

class Example(dict):
    def __init__(self, dictx):
        dct = getattr(__import__("__main__", fromlist=['m']), dictx)
        super(Example, self).__init__(dct)

This will initialize the parent class with data taken from dct. In other words, the empty dictionary has been replaced with the dictionary returned by getattr. So, when print calls the parent's __str__ method, the correct output will be given:

>>> dict1 = {'k1':'v1', 'k2':'v2', 'kn':'vn'}
>>> class Example(dict):
...     def __init__(self, dictx):
...         dct = getattr(__import__("__main__", fromlist=['m']), dictx)
...         super(Example, self).__init__(dct)
...
>>> e = Example('dict1')
>>> print e
{'k2': 'v2', 'k1': 'v1', 'kn': 'vn'}
>>>

An alternate solution would be to define a custom __str__ method for your class that returns self.dictx as a string:

class Example(dict):
    def __init__(self, dictx):
        self.dictx = getattr(__import__("mydicts", fromlist=['m']), dictx)
    def __str__(self):
        return str(self.dictx)

Note however that if you use this approach, there isn't really a reason to inherit from dict since your class is not a new type of dictionary; it just has a dictionary stored as an attribute.

Upvotes: 2

Related Questions