2

I have a class, and there is a dict in it. I want to visit variables in the dict by direct "instance.key" instead of "instance.d[key]". How to do that?

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.fields = {'c': 3, 'd': 4}


def main():
    a = A()
    print(a.a) # 1
    print(a.b) # 2
    print(a.c) # currently raise Exception, I want it to print 3
    print(a.d) # currently raise Exception, I want it to print 4


if __name__ == '__main__':
    main()
Linghao.Chen
  • 103
  • 1
  • 1
  • 5

3 Answers3

6

You are able to override object.__getattr__(self, name) method (such methods can be defined to customize the meaning of attribute access for class instances):

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.fields = {'c': 3, 'd': 4}

    def __getattr__(self, item):
        return self.__dict__.get(item) or self.__dict__['fields'].get(item)

a = A()
print(a.a) # 1
print(a.b) # 2
print(a.c) # 3
print(a.d) # 4

Referece link: __getattr__

RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
1

You can also modify __dict__:

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.fields = {'c': 3, 'd': 4}
        self.__dict__ = {**self.__dict__, **self.fields}

And now:

def main():
    a = A()
    print(a.a)
    print(a.b)
    print(a.c)
    print(a.d)


if __name__ == '__main__':
    main()

Gives:

1
2
3
4
U13-Forward
  • 69,221
  • 14
  • 89
  • 114
0

Implement __getattr__ as @RomanPerekhrest suggested. The only problem you could have is that your instance attributes overrides your dict entries. If that is not the expected behaviour, you should implement __getattribute__ instead of __getattr__

Something like this:

class A:
    def __init__(self):
        self.a = 1
        self.b = 2
        self.e = 5
        self.fields = {'c': 3, 'd': 4, 'e': 6}

    def __getattribute__(self, key):
        fields = super().__getattribute__('fields')
        if key == 'fields':
            return fields

        try:
            return fields[key]
        except KeyError:
            return super().__getattribute__(key)

a = A()
print(a.a) # 1
print(a.b) # 2
print(a.c) # 3
print(a.d) # 4
print(a.e) # 6 (Note that it returns the entry of the dict rather that the instance attribute)
print(a.f) # Raises exception (not in the instance attributes nor in the dict)
Victor Ruiz
  • 1,192
  • 9
  • 9