2

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) ?

2
  • 1
    Why are you using **args at all? This issue never would have come up if you just wrote out your argument list normally and assigned attributes from the argument values normally. Commented Oct 15, 2019 at 9:22
  • 1
    It doesn't look like you even want to support arbitrary extra user-provided names, judging by those __getitem__ and __setitem__ methods (and arbitrary user-provided names wouldn't work with the code completion you're after either). Allowing callers to specify arbitrary keywords is the entire design purpose of **. Commented Oct 15, 2019 at 9:24

3 Answers 3

3

Use setattr.

for name, value in args.items():
    setattr(self, name, value)
Sign up to request clarification or add additional context in comments.

3 Comments

ee = HoldingStuff(e='2354345') throws ValueError: not enough values to unpack (expected 2, got 1)
The first line should probably be for name, value in args.items():.
@Dion thanks worked quite nicely! I edited the answer accordingly and accepted it.
1

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)

Comments

0

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]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.