refactoring so that multiple changes can be made with one variable?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John Salerno

    #1

    refactoring so that multiple changes can be made with one variable?

    My code is below. For now I'm focusing on the lines where health (and
    armor) are increased in each character class. Let's say I decided to
    change the amount of increase in the future. As it is now, I'd have to
    go to each character class and change the number so that each is still
    in a good relation to the other (right now: 3, 2, 1; later: perhaps 4,
    3, 2, 1, if I added a new class -- i.e., change Fighter from 3 to 4,
    Thief from 2 to 3, in other words increase them all by 1). So instead of
    changing each one, is there a simple, clean way of just changing a
    single number so that this change is reflected in all classes? Hope that
    makes sense.



    class Character(objec t):
    def __init__(self, name, strength, dexterity, intelligence):
    self.name = name
    self.health = 10
    self.armor = self.attack = self.defense = self.magic_atta ck = \
    self.magic_defe nse = 0
    self.strength = strength
    self.dexterity = dexterity
    self.intelligen ce = intelligence
    self.adjust_att ributes()

    def adjust_attribut es(self):
    pass


    class Fighter(Charact er):
    def adjust_attribut es(self):
    self.health += 3
    self.armor += 3
    self.attack += 2
    self.defense += 2
    self.strength += 1


    class Thief(Character ):
    def adjust_attribut es(self):
    self.health += 2
    self.armor += 2
    self.attack += 1
    self.defense += 1
    self.magic_defe nse += 1
    self.dexterity += 1


    class Mage(Character) :
    def adjust_attribut es(self):
    self.health += 1
    self.armor += 1
    self.magic_atta ck += 2
    self.magic_defe nse += 2
    self.intelligen ce += 1
  • Paddy

    #2
    Re: refactoring so that multiple changes can be made with one variable?


    John Salerno wrote:
    My code is below. For now I'm focusing on the lines where health (and
    armor) are increased in each character class. Let's say I decided to
    change the amount of increase in the future. As it is now, I'd have to
    go to each character class and change the number so that each is still
    in a good relation to the other (right now: 3, 2, 1; later: perhaps 4,
    3, 2, 1, if I added a new class -- i.e., change Fighter from 3 to 4,
    Thief from 2 to 3, in other words increase them all by 1). So instead of
    changing each one, is there a simple, clean way of just changing a
    single number so that this change is reflected in all classes? Hope that
    makes sense.
    >
    >
    You could keep a handle on all object instances created then go through
    the objects making appropriate changes, e.g:


    class Character(objec t):
    instances = []
    def __init__(self, name, strength, dexterity, intelligence):
    instances.appen d(self)
    # as before ...
    def mod_instances(s elf):
    for inst in instances:
    inst.some_prope rty += 1 # or whatever
    # (Untested)

    - Paddy.

    Comment

    • John Salerno

      #3
      Re: refactoring so that multiple changes can be made with one variable?

      Paddy wrote:
      You could keep a handle on all object instances created then go through
      the objects making appropriate changes, e.g:
      >
      >
      class Character(objec t):
      instances = []
      def __init__(self, name, strength, dexterity, intelligence):
      instances.appen d(self)
      # as before ...
      def mod_instances(s elf):
      for inst in instances:
      inst.some_prope rty += 1 # or whatever
      # (Untested)
      But doesn't this require that the change be predetermined so you can
      code it into the method?

      I don't necessarily need a programmatic way to do this, just a simple
      way to go back to the code and edit a single thing, instead of having to
      update all the numbers.

      Comment

      • James Stroud

        #4
        Re: refactoring so that multiple changes can be made with one variable?

        John Salerno wrote:
        My code is below. For now I'm focusing on the lines where health (and
        armor) are increased in each character class. Let's say I decided to
        change the amount of increase in the future. As it is now, I'd have to
        go to each character class and change the number so that each is still
        in a good relation to the other (right now: 3, 2, 1; later: perhaps 4,
        3, 2, 1, if I added a new class -- i.e., change Fighter from 3 to 4,
        Thief from 2 to 3, in other words increase them all by 1). So instead of
        changing each one, is there a simple, clean way of just changing a
        single number so that this change is reflected in all classes? Hope that
        makes sense.
        >
        >
        >
        class Character(objec t):
        def __init__(self, name, strength, dexterity, intelligence):
        self.name = name
        self.health = 10
        self.armor = self.attack = self.defense = self.magic_atta ck = \
        self.magic_defe nse = 0
        self.strength = strength
        self.dexterity = dexterity
        self.intelligen ce = intelligence
        self.adjust_att ributes()
        >
        def adjust_attribut es(self):
        pass
        >
        >
        class Fighter(Charact er):
        def adjust_attribut es(self):
        self.health += 3
        self.armor += 3
        self.attack += 2
        self.defense += 2
        self.strength += 1
        >
        >
        class Thief(Character ):
        def adjust_attribut es(self):
        self.health += 2
        self.armor += 2
        self.attack += 1
        self.defense += 1
        self.magic_defe nse += 1
        self.dexterity += 1
        >
        >
        class Mage(Character) :
        def adjust_attribut es(self):
        self.health += 1
        self.armor += 1
        self.magic_atta ck += 2
        self.magic_defe nse += 2
        self.intelligen ce += 1
        The place to do this seems to be in the Character class.

        class Character(objec t):
        _health_base_in c = 1
        _armor_base_inc = 1
        # etc
        def __init__(self, name, strength, dexterity, intelligence):
        self.name = name
        self.health = 10
        self.armor = self.attack = self.defense = self.magic_atta ck = \
        self.magic_defe nse = 0
        self.strength = strength
        self.dexterity = dexterity
        self.intelligen ce = intelligence
        self.adjust_att ributes()

        def adjust_attribut es(self):
        pass

        class Mage(Character) :
        # for symmetry with Character
        _health_char_in c = 1
        _armor_char_inc = 1
        # etc
        def adjust_attribut es(self):
        self.health += self._health_ch ar_inc + self_health_bas e_inc
        self.armor += self._armor_cha r_inc + self._armor_bas e_inc
        # etc

        James

        --
        James Stroud
        UCLA-DOE Institute for Genomics and Proteomics
        Box 951570
        Los Angeles, CA 90095


        Comment

        • Paddy

          #5
          Re: refactoring so that multiple changes can be made with one variable?


          John Salerno wrote:
          Paddy wrote:
          >
          You could keep a handle on all object instances created then go through
          the objects making appropriate changes, e.g:


          class Character(objec t):
          instances = []
          def __init__(self, name, strength, dexterity, intelligence):
          instances.appen d(self)
          # as before ...
          def mod_instances(s elf):
          for inst in instances:
          inst.some_prope rty += 1 # or whatever
          # (Untested)
          >
          But doesn't this require that the change be predetermined so you can
          code it into the method?
          >
          I don't necessarily need a programmatic way to do this, just a simple
          way to go back to the code and edit a single thing, instead of having to
          update all the numbers.
          I just put in a simple version of mod_instances. mod_instances could
          take a function as an argument the napply the function to all
          instances, e.g:

          def mod_func1(inst) :
          inst.abc += inst.xyz # or whatever

          class Character(objec t):
          instances = []
          def __init__(self, name, strength, dexterity, intelligence):
          instances.appen d(self)
          # as before ...
          def mod_instances(s elf, mod_func):
          for inst in instances:
          mod_func(inst)

          You can define different mod_func, like mod_func1 to make whatever
          changes to the instances.

          Comment

          • Steven D'Aprano

            #6
            Re: refactoring so that multiple changes can be made with one variable?

            On Tue, 14 Nov 2006 10:41:53 -0500, John Salerno wrote:
            My code is below. For now I'm focusing on the lines where health (and
            armor) are increased in each character class. Let's say I decided to
            change the amount of increase in the future. As it is now, I'd have to
            go to each character class and change the number so that each is still
            in a good relation to the other (right now: 3, 2, 1; later: perhaps 4,
            3, 2, 1, if I added a new class -- i.e., change Fighter from 3 to 4,
            Thief from 2 to 3, in other words increase them all by 1). So instead of
            changing each one, is there a simple, clean way of just changing a
            single number so that this change is reflected in all classes? Hope that
            makes sense.
            Cutting your code down to the minimum that exhibits the behaviour you want:

            class Character(objec t):
            def __init__(self, name, strength, dexterity, intelligence):
            self.name = name
            self.health = 10
            # and so on...
            self.adjust_att ributes()
            def adjust_attribut es(self):
            pass


            class Fighter(Charact er):
            def adjust_attribut es(self):
            self.health += 3

            class Thief(Character ):
            def adjust_attribut es(self):
            self.health += 2

            etc.

            Sounds like you want some sort of factory function that returns a class:

            # WARNING: untested
            def make_character_ class(name, adjustments):
            class klass(Character ):
            _adjustments = {}
            def adjust_attribut es(self):
            for key, value in self._adjustmen ts.items():
            x = getattr(self, key)
            setattr(self, key, x + item)

            setattr(klass, klass.__name__, name)
            setattr(klass, klass._adjustme nts, adjustments)
            return klass


            And now you use it like this:

            Fighter = make_character_ class('Fighter' , {'health': 3})
            Thief = make_character_ class('Thief', {'health': 2})

            Now you can easily change the adjustments, all in just a few lines.

            Here's another idea:

            character_adjus tments = { 'Fighter': {'health': 3},
            'Thief': {'health': 2},
            'Mage': {'intelligence' : 3, 'strength': -1}
            }

            and change the make_character_ class factory function above to only take a
            single argument, name. Now if you decide you want to *programmatical ly*
            adjust the adjustments, you can do this:

            # still untested...
            for key in character_adjus tments:
            for attribute, value in key.items():
            # adjust the values to make up for my poor choices
            character_adjus tments[key][attribute] = value + 1

            (but of course you must do this BEFORE creating your character classes!)


            And last but most certainly not least, you can separate the adjustment
            values into (say) an INI file, read them in at run-time and pass those
            values to the factory function above. Then write another function which
            walks through the INI file, adjusting the values in place as needed. This
            is obviously going to take the most work, so I strongly suggest you don't
            go down this path unless you really have to.


            --
            Steven D'Aprano

            Comment

            • Neil Cerutti

              #7
              Re: refactoring so that multiple changes can be made with one variable?

              On 2006-11-15, Dennis Lee Bieber <wlfraed@ix.net com.comwrote:
              On Wed, 15 Nov 2006 18:57:39 +1100, Steven D'Aprano
              ><steve@REMOVEM E.cybersource.c om.audeclaimed the following in
              comp.lang.pytho n:
              >And last but most certainly not least, you can separate the
              >adjustment values into (say) an INI file, read them in at
              >run-time and pass those values to the factory function above.
              >Then write another function which walks through the INI file,
              >adjusting the values in place as needed. This is obviously
              >going to take the most work, so I strongly suggest you don't
              >go down this path unless you really have to.
              >
              Nice to see I wasn't the only one to consider extending to an
              INI file for this <G>
              Coincidentally, I'm just reading "The Pragmattic Programmer" for
              the first time. One of guidelines is to pry the details ut of the
              code if they might change. The above advice seems like a perfect
              example.

              --
              Neil Cerutti
              For those of you who have children and don't know it, we have a
              nursery downstairs. --Church Bulletin Blooper

              Comment

              Working...