Lpythw: Help RE dict and class ex

I’m new to python and need help.

Here’s the ex44_4 code:

def Person_new(name, age, eyes):
    person = {
        "name": name,
        "age": age,
        "eyes": eyes,
    }

    def talk(words):
        print(f"I am {person['name']} and {words}")

    person['talk'] = talk

    return person

becky = Person_new("Becky", 39, "green")

becky['talk']("I am talking here!")

I get that but I’m then asked to;

  1. Add a new function hit(), which makes one person hit another person.
  2. Give people hit points in their dict and have hit() randomly reduce each person’s hit points using random().
  3. Have the code run a little fight club using loops to make different people battle.

I’ve been at a week with no solution and am quite frustrated. I’m producing line after line of code running down a rabbit hole to nowhere while knowing this can be done with just a few lines… The kicker is that the next exercise introduces classes and asks me to do this again with classes, which it says is the correct way to do this and more importantly, to not do it as asked in ex44_4!!! I’m at 6s and 7s…

Here is the class ex I’m supposed to add HP and fights to:

class Person(object):

    def __init__(self, name, age, eyes):
        self.name = name
        self.age = age
        self.eyes = eyes

    def talk(self, words):
        print(f"I am {self.name} and {words}")

becky = Person("Becky", 39, "green")
becky.talk("I am talking here!")

I’m sure the code is rather simple but I’m just not seeing it atm. I looked at Python documentation too but it stops making sense after a few words… and there’s no examples that make sense to me. I don’t know anyone IRL who can help and I just need some simple Python to English dummy talk :slight_smile: Thank you.

Highly recomment @AlSweigart 's post

To add the dict you need to modify this part of the code:

def Person_new(name, age, eyes):
    person = {
        "name": name,
        "age": age,
        "eyes": eyes,
    }

Perhaps something like

def Person_new(name, age, eyes):
    person = {
        "name": name,
        "age": age,
        "eyes": eyes,
        "hit_points": 10,
    }

Then your hit function is pretty much reducing that:

def hit(person):
    person['hit_points'] -= 1

Hi Andy,
Thansk for the reply but I’m still lost. How do I “reduce each person’s HP using random()”? Or the “fight club”? I don’t get how to use a function to change dict values let alone class values (if that’s what they’re even called).

I’ve gone through the previous 43 exercise alright but I’m not seeing this.

class Person(object):

    def __init__(self, name, age, eyes, HP):
        self.name = name
        self.age = age
        self.eyes = eyes
        self.HP = HP

    def talk(self, words):
        print(f"I am {self.name} and {words}")

    def hit(person):
        person['HP'] -= random(1, 4)

tom = Person("Tom", 40, "hazel", 22)
dick = Person("Dick", 88, "brown", 18)
becky = Person("Becky", 39, "green", 16)
becky.talk("I am talking here!")

I can’t get this to work. ‘HP’ isn’t "defined. Neither is “random.” I just don’t know.

Why not start with the easier approach first?

Hi Elis,

Doesn’t seem easier to me… I need a translation just for the first paragraph. But I appreciate the suggestion.

It would help to start from the beginning:

I’m going through, “Learn Python the Hard Way, 5th Ed” and these are exercises 44.4 and 45. It’s been alright up to this point but I’m at sea with these two, especially since 45 says to not code like you’re asked in 44… which is fine since I don’t know how to do 44 but I also don’t get 45… This is the first exercise on/with classes so I imagine that the answer is quite simple but for the life of me I’m not seeing it (again, for either ex). I don’t know anyone IRL to ask stupid questions or get hints or clarifications and when I read the documentation I feel like an idiot and even more hopeless.

It might be worth trying a different learning method if the approach in Learn Python the Hard Way isn’t clicking for you.

I came here…

Here’s the code that works:

import random


class Person(object):

    def __init__(self, name, age, eyes, HP):
        self.name = name
        self.age = age
        self.eyes = eyes
        self.HP = HP

    def talk(self, words):
        print(f"I am {self.name} and {words}")

    def hit(self, person):
        damage = random.randint(1, 4)
        person.HP -= damage
        print(
            f"{self.name} hit {person.name} for {damage} damage! {person.name}'s HP is now {person.HP}")


tom = Person("Tom", 40, "hazel", 22)
dick = Person("Dick", 88, "brown", 18)
becky = Person("Becky", 39, "green", 16)

becky.talk("I am talking here!")
tom.hit(dick)  # Example usage

Result:

I am Becky and I am talking here!
Tom hit Dick for 4 damage! Dick's HP is now 14

That won’t help you. You need to understand what’s causing errors like 'HP' isn't defined or 'random' is not defined, and so on. These topics are all covered in the official Python tutorial, e.g., Modules.

Hello,

a potential solution is possible using only functions as per the original stated problem. However, I do agree that using classes is preferrable.

Note that in the snippet provided, two items have been added to the dictionary: “points” and “points_awarded”. The first keeps track of the cummulative points of a player - assigned 100 at the start of the game. The second is the number of points awarded to each player every time that they are randomly selected to do the “hitting”. A safety check has been added to ensure that a player is not chosen to both provide a hit and to receive a hit.

The very last line of the script is to verify this: “Give people hit points in their dict” per requirement in problem 2. Note the points in the dict.

I have added commentary within the snippet to provide guidance.

from random import randint, choice

def person_new(name, age, eyes, words_to_add):

    person = {
        "name": name,
        "age": age,
        "eyes": eyes,
        'points': 100,  # Give each player 100 points to start - shows up in their 'dict'
        'points_awarded': 5
        }

    def talk(words):
        print(f"I am {person['name']} and {words}.")

        person['talk'] = talk

    talk(words_to_add)

    return person

# One person hit another person implies providing two arguments
def hit(p1, p2): # p1 hits p2

    p1['points'] = p1['points'] + p1['points_awarded']  # awarded 5 points per hit
    p2['points'] = p2['points'] - randint(1, 10) # deducted random value

# Create players
becky = person_new("Becky", 39, "green", 'hello')
john = person_new('John', 28, 'hazel', 'goodbye')
sam = person_new('Sam', 31, 'brown', 'good afternoon')
roger = person_new('Roger', 24, 'green', 'good day')

# Place players into a list for fetching
player_list = [becky, john, sam, roger]

# Perform 10 loops (can choose your own number)
for loops in range(1, 10):

    # Select players for hit and receive
    first_player = choice(player_list)
    second_player = choice(player_list)

    # Ensure players do not hit themselves
    while first_player == second_player:
        second_player = choice(player_list)

    # One player hits the other player
    hit(first_player, second_player)


print('\nPlayer points after 10 rounds:')
print('-----------------------------')
# Player accumulated points
print(f'{"Becky points":<13}{becky['points']:>3}')
print(f'{"John points:":<13}{john['points']:>3}')
print(f'{"Sam points:":<13}{sam['points']:>3}')
print(f'{"Roger points:":<13}{roger['points']:>3}')

# "Give people hit points in their dict ..."
print("\nPrint Becky's dict:", becky)

The test results from the snippet provided, we get:


I am Becky and hello.
I am John and goodbye.
I am Sam and good afternoon.
I am Roger and good day.

Player points after 10 rounds:
-----------------------------
Becky points 115
John points: 105
Sam points:   89
Roger points:100

Print Becky's dict: {'name': 'Becky', 'age': 39, 'eyes': 'green', 'points': 115, 'points_awarded': 5, 'talk': <function person_new.<locals>.talk at 0x000001A28140D440>}

Give this one a try.

Hope this helps. Good luck!

Hi Elis and Paul!

Elis, thank you for the section of code. The whole self thing is totally new to me so it helps, a bit, to see it used in another function. I’ve tried adding other like functions (a cash one for example) and I’m getting them to work. However, I’m still stuck on the looping fight club. If I just have two fighters, I’m okay, but with three, I’m stuck. I can’t break my loop, eliminate a KO’d fighter, or pass values (all depending on which functions I’ve tried to run…).

Paul, wow… I wasn’t totally wrong but was way off… so hit() is outside the class, correct? Then I can access class variables like, [‘points’], like this???

Alright, get ready for an eyesore, headache, belly laugh, or head slap. Here’s my non-working code…

import random

class Person(object):

    def __init__(self, name, age, eyes, HP):
        self.name = name
        self.age = age
        self.eyes = eyes
        self.HP = HP

    def talk(self, words):
        print(f"I'm {self.name} and I'm saying {words}")

    def hit(self, person):
        damage = random.randint(1, 4)
        person.HP -= damage
        print(f"{self.name} hit {person.name} for {damage} points!")
        return person.HP

    def fighter_select(self, person1, person2):
        #select the 1st fighter
        fighter1 = random.randint(1, 3)
        if fighter1 == 1 and self.HP > 0:
            fighter1 = self
            #select the 2nd fighter and check of +HP, if -, choose another
            #or if rest are -, end fight, declare winner
            fighter2 = random.randint(2, 3)
            if fighter2 == 2 and person1.HP > 0:
                fighter2 = person1
                return fighter1, fighter2
            elif fighter2 == 2 and person1.HP <=0:
                if person2.HP > 0:
                    fighter2 = person2
                return fighter1, fighter2
            else:
                print(f"{fighter1.name} wins!")
                     
        #check if self has HP
        elif fighter1 == 1 and self.HP <= 0:
            fighter1 = person1
            fighter2 = person2
            #check is person2 has HP, if not, break w/ winner
            if fighter2.HP <= 0:
                print(f"{fighter1.name} wins!")      
            return fighter1, fighter2
        elif fighter1 == 1 and self.HP and person1.HP <= 0:
            fighter1 = person2
            print(f"{person2.name} wins!")
            
        elif fighter1 == 2 and person1.HP > 0:
            fighter1 = person1
            fighter2 = random.randint(1, 2)
            if fighter2 == 1 and self.HP > 0:
                fighter2 = self
                return fighter1, fighter2
        elif fighter1 == 2 and person1.HP <= 0:
            fighter1 = person2
        elif fighter1 == 2 and person1.HP and self.HP <= 0:
            fighter1 = person1
            print(f"{person1.name} wins!")
        elif fighter1 == 3 and person2.HP > 0:
            fighter1 = person2
        elif fighter1 == 3 and person2.HP <= 0:
            fighter1 = self
        elif fighter1 == 3 and person2.HP and self.HP <= 0:
            fighter1 = person2
            print(f"{person2.name} wins!")


    def fight_club(self, person1, person2):
        while self.HP or person1.HP or person2.HP > 0:
            fighter1 = ''
            fighter2 = ''
            fighter1, fighter2 == self.fighter_select(tom, harry)
            fighter1.hit(fighter2)
            if fighter1.HP <= 0:
                print(f"{fighter1.name} has been KO'd!")
            elif fighter2.HP <= 0:
                print(f"{fighter2.name} has been KO'd!")
            else:
                print(f"{self.name} has been KO'd!") 
            

          

becky = Person("Becky", 33, "green", 20)
tom = Person("Tom", 38, "hazel", 24)
harry = Person("Harry", 35, "blue", 22)

becky.fight_club(tom, harry)

I know it’s jacked. I’ve tried variations on the ()'s and other ones I’ve deleted. This is just the least borked… My fight_club() I thought I should use a while loop and break when only one fighter’s still standing, but I couldn’t break the loop (I had breaks in there and in other ()'s but the loop was eternal, I’m still learning the boolean tables). I hope this helps y’all see just how little I know and how much help I need. I think my fighter_select() is long and probably redundant but I was trying to achieve your fighter filter…

Thanks for helping the hopefully not hopeless :slight_smile:

I would recommend checking your script as you’re developing it (a continuous self feedback loop) and asking yourself if you can condense it futher to do away with unecessary lines of code. For example, take these two lines located in the hit method:

damage = random.randint(1, 4)
person.HP -= damage

Unless you’re going to be passing the variable damage to another part of your script, you don’t need it as an intermediary variable. You can just write:

person -= random.randint(1,4)

The less lines of code, the cleaner it will look, easier to read, and the easier to debug if and when needed.

This line here, doesn’t make sense. Not sure what you are going after but it is invalid. Please delete it and reassess.

fighter1 = self

I recommend having another look at your figher_select method. There appears to be far too many elif conditional statements. I am sure that it can be condensed further.

You no longer need to include the word object when creating classes when using Python v3.x. This is v2.x legacy.

To keep track of the players that are playing the game, you can add them to a list that is a class attribute like this so that it can be referenced by all objects (players):

from random import choice

class Person:

    players = []  # This is a class attribute (variable) - visible to all objects

    def __init__(self, name, age, eyes):

        # These are instance (i.e, object) attributes (variables)
        self.name = name
        self.age = age
        self.eyes = eyes
        self.HP = 100  # Start each player with 100 points (kind of like Monopoly)

        # As you create new players, add them to the list
        Person.players.append(self.name)


# Create players via 'instantiation'
becky = Person("Becky", 39, "green")
john = Person('John', 28, 'hazel')
sam = Person('Sam', 31, 'brown')
roger = Person('Roger', 24, 'green')

# Verify players are in the list:
print('\n', Person.players, sep='')

# Randomly select a player:
print('\nPlayer randomly selected:', choice(Person.players))

When you run it for testing purposes, you will get this:

['Becky', 'John', 'Sam', 'Roger']

Player randomly selected: John

Thus, when you want to select a player, you can do so from the list which happens to be a class variable and is “seen” by all the players. This is how you should start your test program. Start small and then slowly build up, always testing and verifying along the way.

I quickly referenced the book that you are reading. It covers a lot of topics in a relatively small amount of pages. For a novice, this might feel rushed because it assumes that one is grasping all the concepts rather quickly. Please do reference the book that I recommended in my previous post. It teaches you the language itself … not so much its application via projects. However, the better grounded you are in the language and core concepts, the easier it will be to develop applications such as these since your base will be strong.

Good luck!

“The less lines of code, the cleaner it will look, easier to read, and the easier to debug if and when needed… [ask] yourself if you can condense it futher to do away with unecessary lines of code.”

Early in the book, the author showed an example of condensing several lines into one and it makes sense. My current problem is that I only have one or two Python tools I’m mostly confident/competent with, my proverbial hammer, so I’m looking at everything like they’re a nail. I know they’re not but I don’t fully understand the other tools. I appreciate you clearing some things up. For instance:

Adding a list into a class. Didn’t even cross my mind that that’s possible. With that, I should be able to streamline my fighter selection, hitting, fight club functions. I’m gonna give that a go this week.

And creating unneeded variables (I know of local and global but don’t dare quiz me on 'em yet).

“fighter1 = self” / This line doesn’t make sense.

I didn’t/don’t know how to randomize the three fighters so I thought if I created two fighter variables, to which I could assign one of the three arguments (self, person1, person2), I could then pass them to another function and to be able to reduce the HP… I don’t understand the self thing in that, does every function under the class have to have a self arg? Could hit just be, hit(a, b) and not hit(self, b)?

For that matter, the init has 4? args, (self, name, age, eyes) but the “instances” include HP, and others here have added more, shouldn’t I have to add those to the args?

the book that you are reading. It covers a lot of topics in a relatively small amount of pages. For a novice, this might feel rushed because it assumes that one is grasping all the concepts rather quickly.

I started to feel rushed several chapters ago because it started asking me to look up things in the documentation and apply them. When I looked 'em up, I didn’t understand what I was looking at, reading, let alone how to apply whatever to my exercise. But I’ve ordered that book for the reasons you’ve stated. I do want more practice with the tools but you and Elis are right about needed to know the language and concepts.

Thank you again for your time and help :slight_smile:

This is where focusing on learning the language first and learning additional “tools” will pay dividends. As you further your practice with Python in particular and programming in general, you will start becoming aware that there are of a lot of nuances at play where a deeper understanding of the language is necessary and helpful.

Here is a little code snippet where you can use a dictionary to perform the selection for you. Notice that there are no conditional statements. The selection is done for you based on the value of the dictionary “key” passed in.

# Functions - each with a specific task
def one():
    print('Hello from one.')

def two():
    print('Hola from two.')

def three():
    print('Salut from three.')

def four():
    print('Ciao from four.')

# Create a dictionary with key / value pairs - functions are the 'values'
# Each function may be referenced via the 'key'
nums = {1: one, 2: two, 3: three, 4: four}

# Create a for loop to test and prove that you can call the
# functions via the "key" values
for i in range(1, len(nums)+1):

    nums[i]()

As you can see, having additional “tools” simplifies the code as shown for this particular test case. But you will only become aware of these tools if you first focus on learning the Python language itself. By the way, classes are considered an advanced topic and some may say optional. If you read the book Learning Python, 6E, you will see that there is a whole body of material to understand before even getting aquainted with classes.

When working with classes, the self refers to attributes / methods that pertain to the object itself. In the previous post, we created a list that pertains to the class itself - not the object. These are subtle nuances and concepts that will become apparent the more you practice object-oriented programming (OOP) - concepts that are not limited to Python itself.

Only if you will be using object attributes (i.e., self.name, self.age, etc.) in the body of the method (what you call functions that are created within classes). Otherwise, they are static methods.

This is because you haven’t yet learned Python programmming fundamentals and so you’re being made to feel that you are expected to produce tangible results with the current state of understanding. This why I am generally against this type of approach to learning Python. I am of the opinion that you should first learn the language (there is more than enough material there to keep you very busy I assure you) before any type of “creating” projects and moving on to object-oriented programming. You’ll thank yourself for having done so later. It will make the transition go much more smoothly.

I hope this helps you.