2

I am stuck on how to change the value of attributes that were defined as keyword parameters when a class was initiated. I would like to be able to initialize them to some default value and then change them based on user input but I cannot figure out how.

To illustrate, I made a class that makes boxes based on user input. The user first selects the type of box and then they select the attributes associated with that box. Some attributes, like length, height, width, and color, are attributes of every box, no matter the type. But for some types of boxes, I would like to ask for input about additional parameters. I know I can print out the keyword values using something like:

for key in kwargs:
    print("Here are my keywords and values: %s: %s" % (key, kwargs[key]))

but I don't know how to change their values. Here's the class I made. I'm looking for the part after elif inp = '5':, where I put continue and wrote what I'm trying to do in comments. Obviously, I can't call the variable extra_parameter1, so how do I access it?

class Box():

    def __init__(self, **extra_parameters):
        self.length = 4
        self.height = 3
        self.width = 2
        self.color = None
        self.__dict__.update(extra_parameters)


    def get_parameters(self):#, *extra_parameters):
        inp = 0
        attrs = vars(self)
        while inp != '':
            for i in range(len(attrs)):
                print("{num}. {param}: {value}".format(num=i+1, param=list(attrs.keys())[i], value=list(attrs.values())[i]))
            inp = input("Enter your selection: ")
            if inp == '1':
                self.length = input("Enter the desired length: ")
            elif inp == '2':
                self.height = input("Enter the desired height: ")
            elif inp == '3':
                self.width = input("Enter the desired width: ")
            elif inp == '4':
                self.color = input("Enter the desired color: ")
            elif inp == '5':
                continue
                #self.extra_parameter1 = input("Enter the desired " + extra_parameter1 + ": ")
            elif inp == '6':
                continue
                #self.extra_parameter2 = input("Enter the desired " + extra_parameter2 + ": ")
            elif inp == '':
                print("Accept parameters")


box_type = input("Which box would you like to make?\n1. Spring\n2. Slip\n3. Prototype \n4. Two-spring\n\n")


if box_type == '1':
    spring=Box(spring_strength = 4)
    spring.get_parameters()
elif box_type == '2':
    slip=Box()
    slip.get_parameters()
elif box_type == '3':
    proto=Box()
    proto.get_parameters()
elif box_type == '4':
    two_spring=Box(left_sprint = 8, right_spring = 8)
    two_spring.get_parameters()

1 Answer 1

2

The order of attrs.keys() is undefined, so it can change each time you modify the contents of attrs. And it's not guaranteed that the order will correspond to your hard-coded indexes.

From the Python 3 docs:

Keys and values are iterated over in an arbitrary order which is non-random, varies across Python implementations, and depends on the dictionary’s history of insertions and deletions

It's better to copy the keys into a list first, so you have a fixed (although still arbitrary) order to work with. Then you can safely access all the parameters by index, with no need for hard-coding:

class Box():

    def __init__(self, **extra_parameters):
        self.length = 4
        self.height = 3
        self.width = 2
        self.color = None
        self.__dict__.update(extra_parameters)

    def get_parameters(self):
        inp = 0
        attrs = vars(self)
        keys = [k for k in attrs.keys()] # store keys as a list, in order to fix their order

        while inp != '':
            for i, k in enumerate(keys):
                print("{num}. {param}: {value}".format(num=i+1, param=k.replace('_', ' '), value=attrs[k]))
            inp = input("\nEnter your selection: ")
            if inp == '':
                print("Accept parameters")
            else:
                i = int(inp) - 1
                attrs[keys[i]] = input("Enter the desired {param}: ".format(param=keys[i].replace('_', ' ')))


box_type = input("Which box would you like to make?\n1. Spring\n2. Slip\n3. Prototype \n4. Two-spring\n\n")

if box_type == '1':
    spring=Box(spring_strength = 4)
    spring.get_parameters()
elif box_type == '2':
    slip=Box()
    slip.get_parameters()
elif box_type == '3':
    proto=Box()
    proto.get_parameters()
elif box_type == '4':
    two_spring=Box(left_spring = 8, right_spring = 8)
    two_spring.get_parameters()
Sign up to request clarification or add additional context in comments.

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.