1

I'm using python for creating a Dungeons and Dragons Character Creator, and am currently programming the weapons. I've recreated some code that has failed to work in previous similar environments, and I was wondering about a way for it to work without needing an if statement for each individual variable, so that editing for additional properties and items might be available.

The goal is to create an Weapon(Object) that has only the Properties(variables) associated with it.

Current Code:

class Weapon:
    def __init__(self, finesse, light, thrown, two_handed, versatile):
        property_list = [finesse, light, thrown, two_handed, versatile]
        for prop in property_list:
            if prop != 0:
                self.prop = prop

dagger = Weapon('finesse', 'light', 'thrown', 0, 0)

Currently the variable wouldn't be created for the weapon; thus

dagger.finesse

Does not exist. Ideally 'finesse' would be stored in the variable dagger.finesse, while the variable dagger.two_handed would not be created by the code.

I'm probably overlooking something simple, and there might be duplicate questions, but I can't find a similar question with the answer I'm looking for.

Thank you to all who reply

Edits

Thank you to @WKPlus for some formatting assistance; I'm new to the stackoverflow website

I've realized thanks to @abarnert that the better way to do this is to have the porperties listed in a variable and to check that variable later in the code for the property, like so

class Weapon:
    def __init__(self, finesse, light, thrown, two_handed, versatile):
        property_list = [finesse, light, thrown, two_handed, versatile]
        self.properties = []
        for prop in property_list:
            if prop != 0:
                self.properties.append(prop)

However, I'm still interested in seeing how my original question might be answered, as it could still be useful to run something like my original without the exclusion statement.

11
  • 2
    Why do you want Weapon.finesse to be the string 'finesse' or nonexistent? Wouldn't it be better to have it be, say, a bool that's true for daggers and false for clubs? Commented May 27, 2015 at 2:59
  • Think about how you're going to use this. Do you want to to try: player.weapon.finesse except AttributeError: all over the code? Commented May 27, 2015 at 3:00
  • Ideally, there would be multiple subclasses of Weapon. Commented May 27, 2015 at 3:06
  • 1
    @abarnert I'm an idiot. I could just append the properties to a variable dagger.properties and check that for the values as needed. Commented May 27, 2015 at 3:15
  • 2
    @Bristles I think that makes sense. It separates the weapon properties from the "Weapon class" attributes. You can just check for presence of a particular property (eg if 'thrown' in weapon.properties:), or print out the whole list if needed. Commented May 27, 2015 at 3:17

3 Answers 3

4

You can use **kwargs and setattr:

class Weapon:
    def __init__(self, **kwargs):
        property_list = ['finesse', 'light', 'thrown', 'two_handed', 'versatile']
        for prop in property_list:
            setattr(self, prop, kwargs.get(prop, False))

dagger = Weapon(finesse=True, light=True, thrown=True)

This will look for any of the properties in property_list in the passed arguments and set that attribute on self. If the property isn't found, it gets set to False.

Sign up to request clarification or add additional context in comments.

Comments

3

This would work:

class Weapon:
    def __init__(self, finesse=False, light=False, thrown=False, two_handed=False,
                 versatile=False):
        props = locals()
        props.pop('self')
        for prop, value in props.items():
            if value:
                setattr(self, prop, value)

Now:

dagger = Weapon('finesse', 'light', 'thrown', 0, 0)

or:

dagger = Weapon('finesse', 'light', 'thrown')
  1. I use default arguments that I set to False. So if you do not provide them they are False.

  2. locals() gives you a dictionary of all local variables defined so far. Here, these are the arguments to __init__(). Since you don't want self.self, use props.pop('self') to remove it.

  3. The self.prop = prop does not work.

    For example, if you a class A and a variable x:

    class A(object):
        pass
    x = 1
    

    This:

    for obj in [x]:
        A.obj = obj
    

    gives an attribute obj

    >>> A.obj
    1
    

    where this:

    setattr(A, 'x', x)
    

    gives you an attribute x:

    >>> A.x
    1
    

    You need setattr(self, name, value) to set an attribute programmatically.

Comments

0

Other than using setattr to set attribute, your also can parse your args into a dict and update the __dict__ attribute with it:

class Weapon:
    def __init__(self, finesse, light, thrown, two_handed, versatile):
        property_list = ['finesse', 'light', 'thrown', 'two_handed', 'versatile']
        property_values = dict([(name,eval(name)) for name in property_list])
        self.__dict__.update(property_values)

dagger = Weapon('finesse', 'light', 'thrown', 0, 0)
print dagger.finesse

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.