4

Trying to create objects based on name/value pairs obtained in JSON form

e.g.

json = {'name': 'ruby',
        'type': 'rare',
        'size': {'weight': '5', 'height': '2'}
       }

however the name/values can be optional. So it could also be of the form

json = {'name': 'saph',
        'size': {'height': '4'}
        #'type' and 'height' have been omitted
       }

I attempted

class Gem(object):
    def __init__(self, **params):
        self.name = params['name']
        self.type = params['type']
        self.size = params['size']

gem = Gem(**json)

but it is expecting all parameters to be available.

I want to eventually be able to access properties of the object, e.g.

print(gem.name) #prints 'ruby'
print(gem.type) #prints 'rare'
1
  • 1
    Do you expect gem.name to be defined if json has no name entry? If so, what default value? Commented Aug 23, 2017 at 0:22

3 Answers 3

5

Use get() with a default value:

self.type = params.get('type', '')

Update

A more elegant way of achieving this would be to use the combination of the packages attrs and cattrs. Install them with pip (the minimal version of cattrs is important):

pip install attrs
pip install 'cattrs>=1.0.0rc0'

Then define your class as an attrs dataclass (cattrs doesn't support Python 3.7's standard dataclasses yet, which is why we use attrs):

In [1]: import attr

In [2]: import cattr

In [3]: @attr.s(auto_attribs=True) 
   ...: class Gem: 
   ...:     name: str = None 
   ...:     type: str = None  # Not a good name since it's a keyword, but I'm building upon the structure in the question
   ...:     size: str = None     

And finally to construct an instance from a dictionary (which you possibly parsed from a JSON):

In [4]: cattr.structure({'name': 'saph', 
   ...:         'size': {'height': '4'} 
   ...:         #'type' and 'height' have been omitted 
   ...:        }, Gem)
Out[4]: Gem(name='saph', type=None, size="{'height': '4'}")
Sign up to request clarification or add additional context in comments.

Comments

1

You are trying to access undefined key type when you are doing this self.type = params['type'].

This will throw KeyError.

You might want to use:

self.type = params.get('type', '') #sets self.type to '' empty string
self.type = params.get('type') #sets self.type to None

Comments

0
class Gem(object):
    def __init__(self, **params):
        self.name = params['name'] if 'name' in params else None
        self.type = params['type'] if 'type' in params else None
        self.size = params['size'] if 'size' in params else None

gem = Gem(**json)

I would first check if the key is there if not leave it as None

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.