Search code examples
pythondictionaryclass-instance-variables

Is there any way to get class instance attributes without creating class instance?


Here is the link to my first question: Creating class instance from dictionary?
So I am trying to create class instance from dictionary which holds keys that class has not. For example:

class MyClass(object):
    def __init__(self, value1, value2):
        self.attr1 = value1
        self.attr2 = value2

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'}

Before creating class instance I have to delete this redundant_key from dict

dict.pop('redundant_key', None)
new_instance = MyClass(**dict)

The problem is that I have several classes and several dicts with a lot of keys (I have several responses in json format which are represented as dicts and I want to create objects from this json responses). I already found an interim solution from previous question - how to delete redundant keys. I can create new dict from old dict only with keys that I need:

new_dict = {key: old_dict[key] for key in allowed_keys}

So here is the code:

class MyClass(object):
    def __init__(self, value1, value2):
        self.attr1 = value1
        self.attr2 = value2

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'}
new_instance = MyClass(**{key: dict[key] for key in allowed_keys})

All I need now is to get allowed_keys. So the question - Is there any way to get class instance attributes without creating class instance?


Solution

  • If you insist on using an overly general dictionary to initialize your object, just define __init__ to accept, but ignore, the extra keys.

    class MyClass(object):
        def __init__(self, attr1, attr2, **kwargs):
            self.attr1 = attr1
            self.attr2 = attr2
    
    d = {'attr1': 'value1', 'attr2': 'value2', 'extra_key': 'value3'}
    new_instance = MyClass(**d)
    

    If you can't modify __init__ (as appears to be the case if it inherits from a SQLAlchemy declarative base), add an alternate constructor to accept all the keyword arguments but pick out the ones you need.

    class MyClass(Base):
        @classmethod
        def from_dict(cls, **kwargs):
            # Let any KeyErrors propagate back to the caller.
            # They're the one who forgot to make sure **kwargs
            # contained the right keys.
            value1 = kwargs['attr1']
            value2 = kwargs['attr2']
            return cls(value1, value2)
    
    new_instance = MyClass.from_dict(**d)