implicit item assignment in python objects

Viewed 156

I would like to be able to assign values to class' attributes without specifying them.

What i would like to make work

A)


class HoldingStuff(object):

    def __init__(self, **args):
        self.a = 1
        self.b = '1'
        self.c = 2
        self.d = '3'
        self.e = 4
        for arg in args:
            self[arg] = args[arg]

first = HoldingStuff(a=5)
second = HoldingStuff(d=2, e='2')

Of course i could just use a dictionary within the class which holds the values. There is a big downside to that however, because i can not use code completion for the attributes then. Which makes them hard to reuse and find. (The attributes are an extensive list of mutable parameters for a simulation.)

What does work (and is unpractical)

B)


class HoldingStuff(object):

    def __init__(self, **args):
        self['a'] = 1
        self['b'] = '1'
        self['c'] = 2
        self['d'] = '3'
        self['e'] = 4
        for arg in args:
            self[arg] = args[arg]

What kinda works

C)


class HoldingStuff(MutableMapping):

    def __init__(self, **args):
        self.a = 1
        self.b = '1'
        self.c = 2
        self.d = '3'
        self.e = 4
        for arg in args:
            self[arg] = args[arg]

    def __setitem__(self, k, v) -> None:
        if k =='a':
            self.a = v
        elif k =='b':
            self.b = v
        elif k =='c':
            self.c = v
        elif k =='d':
            self.d = v
        elif k =='e':
            self.e = v
        else:
            print(k, "Not available for class.")

    def __delitem__(self, v) -> None:
        pass

    def __getitem__(self, k) -> _VT_co:
        if k =='a':
            return self.a
        elif k =='b':
            return self.b
        elif k =='c':
            return self.c
        elif k =='d':
            return self.d
        elif k =='e':
            return self.e
        else:
            print(k, "Not available for class.")

    def __len__(self) -> int:
        return 5

    def __iter__(self):
        print("Not implemented")

The functions __setitem__ and __getitem__ seem obvious and repetitive!

Question Is there a way to reduce the source code of example C) to work in an implicit way of example A) ?

3 Answers

Use setattr.

for name, value in args.items():
    setattr(self, name, value)

Thank You for Your comments, which helped me find:

https://stackoverflow.com/a/6760593/3707039

delivered an elegant solution


class HoldingStuff(object):

    def __init__(self, **args):
        self.a = 1
        self.b = '1'
        self.c = 2
        self.d = '3'
        self.e = 4
        vars(self).update(args)

Can't comment because I have less than 50 reputation. In option a,

class HoldingStuff(object):

    def __init__(self, **args):
        self.a = 1
        self.b = '1'
        self.c = 2
        self.d = '3'
        self.e = 4
        for arg in args:
            self[arg] = args[arg]

first = HoldingStuff(a=5)
second = HoldingStuff(d=2, e='2')

you have the lines:

for arg in args:
    self[arg] = args[arg]

yet you insert a string and trying to find its args' index

second  = HoldingStuff(d=2, e='2') #e='2'

I think you should try using:

for arg in range(len(args)):
    self[args[arg]] = args[arg]
Related