[類別篇] 將 dict 轉成階層式屬性 - tsungjung411/python-study GitHub Wiki

basic

class AttrDict(dict):
    def __init__(self, attr_dict):
        self.__dict = attr_dict
    
    def __getattr__(self, name):
        return self.__dict[name]
    
    def __repr__(self):
        return str(self.__dict)

d = AttrDict({
            'A': 'a',
            'b': 'B',
            'C': AttrDict({
                'C1': 'c1',
                'C2': 'c2'
            })
        })

print('d.A:', d.A)
print('d.b:', d.b)
print('d.C:', d.C)
print('d.C.C1:', d.C.C1)

執行結果:

d.A: a
d.b: B
d.C: {'C1': 'c1', 'C2': 'c2'}
d.C.C1: c1

advanced

class Dict(dict):

    def __init__(self, init_dict: dict = {}):
        self.__dict = {}
        for k, v in init_dict.items():
            if type(v) == dict:
                self.__dict[k] = Dict(v)
            else:
                self.__dict[k] = v

    def __setattr__(self, key, value):
        if key == '_Dict__dict':
            super().__setattr__(key, value)
        else:
            self.__dict[key] = value

    def __getattr__(self, key):
        return self.__dict[key]

    def __hasattr__(self, key):
        return key in self.__dict

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

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

    def __repr__(self):
        return repr(self.__dict)

    def copy(self):
        new_dict = Dict()
        for k, v in self.__dict.items():
            if type(v) == Dict:
                new_dict[k] = v.copy()
            else:
                new_dict[k] = v
        return new_dict

    def get(self, key, default=None):
        return self.__dict.get(key, default)

    def items(self):
        return self.__dict.items()

    def keys(self):
        return self.__dict.keys()

    def update(self, new_dict: dict):
        for k, v in new_dict.items():
            self.__dict[k] = v

    def values(self):
        return self.__dict.values()

    # note implemented yet
    #  'clear', 'fromkeys', 'pop', 'popitem', 'setdefault'


d = {'profile': {'name': {'first_name':'tj\'s', 'last_name': 'tsai'}, 'age': 18}}
b = Dict(d)
print(b)

執行結果:

{'profile': {'name': {'first_name': "tj's", 'last_name': 'tsai'}, 'age': 18}}

final solution

class Dict(dict):
    def __init__(self, source = None):
        if source is None:
            super().__init__()
        else:
            super().__init__(source)

        # convert all sub-dict to sub-Dict
        for k, v in self.items():
            if type(v) == dict:
                self[k] = Dict(v)

    def __setattr__(self, key, value):
        if type(value) == dict:
            self[key] = Dict(value)
        else:
            self[key] = value
        
    def __getattr__(self, key):
        return self[key]

    def __dir__(self):
        # list the attributes of the dict, and all of its keys
        return super().__dir__() + [k for k in self.keys()]

    def copy(self):
        # implement the deep copy
        a_copy = Dict()
        for k, v in self.items():
            if type(v) == Dict:
                # recursively copy
                a_copy[k] = v.copy()
            else:
                a_copy[k] = v
        return a_copy