How to implement the __getitem__ dunder method in python to get attribute values?

2.2k Views Asked by At

I have the following code:

class Personne:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getitem__(self, *args):
        keys = list(*args)
        return [self.__dict__[key] for key in keys]


if __name__ == '__main__':
    p = Personne('A', 20)
    # age = p['age']
    # print(age)
    # name = p['name']
    # print(name)
    name, age = p['name', 'age']
    print(name, age)

The uncommented part works fine, but the there is a problem in the commented code. How can i achieve the desired behaviour, which is to get attribute values based on arguments (can be one or many) passed to the getitem method.

Thanks.

2

There are 2 best solutions below

0
Bolat On BEST ANSWER

The problem with passing passing only one string is in that when you call p['age'], the type of *args is a string and therefore list(*args) becomes ['a', 'g', 'e']. When you pass both 'age' and 'name', the *args is interpreted as a tuple and you get the appropriate result. One way to handle this issue could be to check the type of the *args parameter in the getitem(self, *args) method. The following modification would solve the issue you are facing (Python 3), though you might want to clean it a bit.

class Personne:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getitem__(self, *args):
        if isinstance(*args, str):
            return self.__dict__[str(*args)]
        keys = list(*args)
        return [self.__dict__[key] for key in keys]


if __name__ == '__main__':
    p = Personne('A', 20)
    age = p['age']
    print(age)
    name = p['name']
    print(name)
    name, age = p['name', 'age']
    print(name, age)
    
    
CONSOLE OUTPUT : 

20
A
A 20

2
i alarmed alien On

As I'm sure you're aware, currently your code returns an error because keys = list(*args) treats the string age as an iterable and tries to look for a, g, and e in self.__dict__. You could therefore check the type of the argument given to __getitem__ and perform the appropriate transformation of args to get the keys to return:

class Personne:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getitem__(self, args):
        if isinstance(args, str):
            keys = [ args ] # args is a string
        else:
            keys = list(args) # args is a tuple
        return [self.__dict__[key] for key in keys]

Output will be a list of values from self.__dict__.