assigning values in __init__

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Thu Nov 9 08:19:47 EST 2006


On Thu, 09 Nov 2006 10:36:07 +0000, Antoon Pardon wrote:

> On 2006-11-09, Steven D'Aprano <steve at REMOVE.THIS.cybersource.com.au> wrote:
>> On Thu, 09 Nov 2006 12:27:12 +1100, Ben Finney wrote:
>>
>>> John Salerno <johnjsal at NOSPAMgmail.com> writes:
>>> 
>>>> Ben Finney wrote:
>>>> > If you pass a *mapping* of the
>>>> > "I-might-want-to-add-more-in-the-future" values, then you get both
>>>> > explicit *and* expandable, without an arbitrary unneeded sequence.
>>>>
>>>> Do you mean by using the **kwargs parameter?
>>> 
>>> No. 
>>
>> Well, that'll teach me to put words in your mouth.
>>
>> [snip]
>>> If you have a group of named, semantically-related, unsequenced values,
>>> pass them into the function as a mapping object (a dict object).
>>
>> Still, if you are doing this:
>>
>> mapping_object = {"strength": roll_dice(10),
>>     "intelligence":roll_dice(10),
>>     "dexterity":roll_dice(10)}
>> my_character = Character(mapping_object)
>>
>> then there is little benefit to building the dict just for the purposes of
>> passing it to Character(), never to use it again, not when you can do this:
>>
>> my_character = Character(strength: roll_dice(10), 
>>     intelligence:roll_dice(10), dexterity:roll_dice(10))
> 
> But you will have to adapt this if you want extra or different
> characteristics.

Sure, but only in one place:

# now have charisma
my_character = Character(strength=roll_dice(8), 
    intelligence=roll_dice(12), dexterity=roll_dice(20),
    charisma=roll_dice(6))

If all the char attributes are initialised with the same function, it
may make sense to set them in a loop, as you do below. But if they are all
calculated differently, as above, then you lose the benefit of a loop.

> Personnally I would prefer something like:
> 
>   chardict = {}
>   for char in characteristics:
>     chardict[char] = roll_dice(10)
> 
>   my_character = Character(chardict)
> 
> This way you only have to keep your characteristics in one place.

As I do.

Remember, the prerequisite for my suggestion to make sense is that, once
you've created your initial character attributes and stuck them in a dict,
you never use the dict again. Also, I'm assuming the constraint that there
is a manageably small number of character attributes.


>> If you happen to already have collected your character attributes in a
>> mapping object for some other reason, then well and good, pass it into the
>> function. Otherwise, well, I believe the correct container for
>> character attributes is a Character, not a dict.
> 
> What is wrong with keeping the character attributes in a dict in the
> Character?

For the same reason we typically say object.attribute rather than
object.__dict__[attribute]

Perhaps you missed the original post, where one of the constraints was
that character attributes in the game were also object attributes. E.g.

class Character(object):
    def __init__(self, strength):
        self.strength = strength

The question posed was, what is the best way of calling __init__ with
values for those character attributes?

If the character attributes vary at runtime, or there are many of them, or
if they are needed together (rather than individually) in multiple places
apart from Character.__init__, then it makes sense to bundle them up in a
dict and pass the dict around, like Ben and now you are suggesting.

But if the character attributes are not varying, and there are only a few,
and they only get used collectively for Character.__init__, then I don't
believe there is any advantage to putting them in a dict to be used once
and then tossed away.

To give an analogy, if you are writing a coordinate class, you would
likely do something like this:

class Coord(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

If you had a lot of dimensions, you'd change your entire model:

class Coord(object):
    def __init__(self, alist):
        self.coordinates = alist

But it is unlikely that a tactic like this would be worth the extra work:


class Coord(object):
    def __init__(self, mapping_object):
        # check that mapping_object has the right keys
        expected = ['x', 'y']
        for key in expected:
            if key not in mapping_object.keys(): raise KeyError
        # do something with mapping_object
        self.__dict__.update(mapping_object)

mapping = {'x': some_value, 'y': some_value}
point = Coord(mapping)
del mapping # never use it again after construction


-- 
Steven.




More information about the Python-list mailing list