• 0

[Python] Instance variable management


Question

Hi everyone. I've been working with python lately, and have gotten pretty far in just a few days.

I've been playing with classes and things have been running fairly smoothly.

Unfortunately however, I am having a bit of trouble managing instance variables. This idea is totally new to me as, in C++, all objects of a defined class have the same "fields" -in python- belonging to each of them. I know this is the same thing as an object variable in python, and that class variables hold a single value that is shared between all objects in what is called a class variable.

Onto the problem...

class player:
    NoP = 0
    def __init__(self, name, HP = 150, MP = 50):
        player.NoP += 1
        if player.NoP > 1:
            print("You can only have one player! Deleteing self.")
            del self
        else:
            print("Player has been instantiated.")
        name = name
        health = HP
        mana = MP
        damage = 30

    def __call__(health):
        return health

    def attack(self, enemy):
        if enemy().health() > 0:
            enemy().health -= self().damage()
            print("Enemy's health is {0}.".format(enemy().health()))
            if enemy().health() <= 0:
                print("Enemy is now dead.")
                del enemy
        else:
            print("Enemy is dead")
            del enemy

class monster:
    pass

MainChar = player("Lancelot", 300, 150)
MainChar().attack(MainChar)

As you can see, this code is still under development.

I ran the interpreter and everything seems to run quite smoothly until as far as the MainChar().attack(MainChar) method call.

The error I am getting is:

  Quote

File "C:/Documents and Settings/Travis/Desktop/Hack/Python/playerclass.py", line 19, in attack

if enemy().health() > 0:

AttributeError: player instance has no attribute 'health'

I am not sure how to handle this problem because, as far as I can tell, I have properly instantiated the object variable "health" within the definition of the __init__ initialization method.

Could someone explain where I am going wrong?

Link to comment
https://www.neowin.net/forum/topic/889424-python-instance-variable-management/
Share on other sites

8 answers to this question

Recommended Posts

  • 0

You need to add "self." to all the variables in your initializer. If you don't, I think that Python assumes that they are classifier scope (static), and not instance scope.

So instead of:

        name = name
        health = HP
        mana = MP
        damage = 30

You should have:

        self.name = name
        self.health = HP
        self.mana = MP
        self.damage = 30

  • 0

Thanks a lot.

I did what you guys suggested and everything works now.

I do have a question, though. I have been reading the book "A byte of Python" and it left me under the assumption that calls to an object had to have parentheses at the end (ie. MainChar().method(...)) so that a differentiation could be made between calls to the class (player.method()) and calls to an object?

Is this not the case?

  • 0

MyClass.classMethod1() // equivalent to C++ MyClass::staticMethod1();
myObject = MyClass() // equivalent to C++ MyClass* myObject = new MyClass();
myObject.method1() // equivalent to C++ myObject->method1();
myObject() // uses myObject as callable entity - equivalent to a C++ functor
myObject().method2() // calls method2() on the return value of callable object myObject (which is not necessarily a MyClass)

In Python, everything is an object, including functions (and classes and modules), so when you call a function you are basically just invoking a particular type of callable object. When you call a class, it returns a new instance of its type. When you call a function, well it invokes the code within that function, but not everything is callable.

Adding parentheses after an identifier denotes a Call.

  • 0

Thanks again for everyone's help.

Unfortunately I have another question already about a different project, so why not post it here?

# Filename: addrbook.py

class addrbook:
    index = {}

    def search():
        Contact_Name = input("Enter the name of the person to search for\n\
i.e. John Smith\n--> ")
        if str(Contact_Name) in addrbook.index:
            print("{0}".format(addrbook.index[Contact_Name]))

        else:
            print("The person you searched for does not exist.\n\
You may want to use the add function to include their information.")

    def add():
        Contact_Name = input("Enter the name of the person to add.\n\
i.e. Mai Friend\n--> ")
        Contact_Info = input("Enter the information for your friend\n\
with commas between each piece of information.\n\
i.e. 555-1234, friendemail@emailhost.com, South Park Avenue\n--> ")
        addrbook.index[str(Contact_Name)] = str(Contact_Info) + "\n"
        print("Contact successfully added!")

    def remove():
        Contact_Name = input("Enter the name of the contact to remove.\n\
i.e. Kate Olsen\n--> ")
        del addrbook.index[str(Contact_Name)]
        print("Contact successfully removed!")

    def browse():
        for i in addrbook.index:
            print(i)
        print("The above are all the contacts you have listed")

    def saveindex():
        with open("addrbook.txt", "a") as f:
            for i in addrbook.index:
                f.write(i) #write the name of the contact on the first line
                f.write("\n") #write an endline to differentiate
                f.write(addrbook.index[i]); #write the contact info for the contact

    def openindex():
        with open("addrbook.txt") as f:
            NoL = len(f.readlines()) #get number of lines in the file (This was part of a previous fix, it's not necessary now)
        with open("addrbook.txt") as f:
            while True:
                key = f.readline() #assign the first line to the "key" of the index dictionary
                value = f.readline() #assign the second line to the "value" of the corresponding key in the index dictionary
                addrbook.index[str(key)] = value

import os
if os.path.isfile("addrbook.txt True:
    addrbook.openindex()

print("Search Contacts .... S")
print("Add Contact ........ A")
print("Remove Contact ..... R")
print("Browse Contacts .... B")
print("Quit ............... Q")

while True:
    opt = str(input("\nWhich action would you like to take?: "))

    if str(opt) == 'S':
        addrbook.search()
    elif str(opt) == 'A':
        addrbook.add()
    elif str(opt) == 'R':
        addrbook.remove()
    elif str(opt) == 'B':
        addrbook.browse()
    elif str(opt) == 'Q':
        addrbook.saveindex()
        break
    else:
        print("invalid input.")

The project (my own) is to make an address book with the ability to search, browse, add, and remove contacts, store them into a file (which, after I get things working, might be changed to 'pickling') and have the ability to open things up.

I did some fixing and adjusting and things seemed to be taking a turn for the better, but now when I run the program, the following happens:

1. On the first run of the program, everything is fine. All functions work, storing of contacts to blank file is fine.

2. On second run of the program, IDLE prints =====RESTART==== as normal, but then nothing but the prompt (>>>) appears. I cannot enter anything into the prompt and no further action is taken for any amount of time.

As you can see, the problem I'm having here is with the fact that I have no idea what could be going wrong since there are no error messages.

The only change I made before this particular problem occurred was the addition of a ( + "\n") to the "add" function in addrbook:

addrbook.index[str(Contact_Name)] = str(Contact_Info) + "\n"

  • 0

On the second run, addrbook.txt has been created, so the function addrbook.openindex() is called. It contains an infinite loop (while True:). Hence, the program never leaves that function. :)

Btw, you are aware that you are using static methods and fields, right? In C++ terms, this is as if you had put the word "static" in front of everything in your class. In Python you declare an instance method like this:

def myMethod(self):
     #code

and instance fields by initializing them in the __init__ method:

def __init__(self);
     self.field1 = "a string"
     self.field2 = 0

  • 0

Thanks for the help, Dr_Asik!

I was actually able to fix the problem by changing the lines at the beginning of the program to:

if os.path.isfile(savefile) == True:
    with open(savefile, 'rb) as f:
        addrbook.index = pickle.load(f)

and towards the end:

elif str(opt) == 'Q':
        if os.path.isfile(savefile) == True:
            os.remove(savefile)
        with open(savefile, 'wb') as f:
            pickle.dump(addrbook.index, f)
        break

Everything works with pickles!

And yes, I am aware that I was making static methods. The design for this class is set to operate on index, and nothing else.

For that reason, I made all the methods static, as it would be unnecessary (and unusual) to instantiate a class that works by operating on a single dictionary.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • Yeah!!!! I was damn well shocked to see the tab with previous file open when I clicked on the new file. It had private info and I was opening another file to show another person. That was weird
    • The article says the whole setup is about the size of a pencil case which sounds pretty portable to me.
    • I thought router has to have 6 Ghz band to be called wifi-7, guess I was wrong...
    • I have the Pixel 9 Pro XL...Unless this thing is "leaps and bounds" faster than the 9, I'll pass. And by leaps and bounds, I don't mean on benchmarks. "Real world" faster. Most people don't even come close to topping out the performance of their phones. Tensor G5 is Google's most powerful chip to date, boasting a staggering 36 percent performance leap over G4.
    • MIT's stunning 'bubble wrap' device squeezes water out from thin air even in deserts by Sayan Sen Image by Matteo Roman via Pexels Massachusetts Institute of Technology (MIT) engineers have built a new kind of device that can pull clean drinking water straight out of the air—no electricity needed. It’s designed for areas where water is scarce and traditional sources like rivers or lakes aren’t reliable. Right now, more than 2.2 billion people globally don’t have access to safe drinking water. In the United States alone, 46 million face water insecurity, with either no running water or water that’s not safe to drink. This new device, called an Atmospheric Water Harvesting Window (AWHW), uses a unique hydrogel panel that looks like black bubble wrap. These dome-shaped bubbles soak up water vapor from the air, especially at night when humidity is higher. During the day, sunlight makes the vapor inside evaporate. That vapor then condenses on a glass surface and drips down through a tube, turning into drinkable water. The AWHW doesn’t rely on power sources like batteries or solar panels. It’s completely passive, meaning it works on its own. The team tested a meter-sized panel in Death Valley, California, one of the driest places in North America, and got between 57.0 and 161.5 milliliters of water per day even with humidity as low as 21 percent. That’s more than what other similar passive devices have managed. “We have built a meter-scale device that we hope to deploy in resource-limited regions, where even a solar cell is not very accessible,” said Xuanhe Zhao, a professor at MIT. “It’s a test of feasibility in scaling up this water harvesting technology. Now people can build it even larger, or make it into parallel panels, to supply drinking water to people and achieve real impact.” Another cool part of the design is how they kept the water safe to drink. Usually, these kinds of hydrogels use salts like lithium chloride to absorb more vapor but that can lead to salt leaking into the water, which isn’t ideal. To solve this, MIT’s team mixed in glycerol, a compound that helps keep salt locked inside the gel. In testing, the lithium ion concentration in the harvested water stayed below 0.06 ppm (parts per million), which is way below the safe limit. The hydrogel domes also give the material more surface area, letting it collect more vapor. The outer glass panel is coated with a special polymer film that helps cool the glass, making it easier for vapor to condense. “This is just a proof-of-concept design, and there are a lot of things we can optimize,” said lead author Chang Liu, now a professor at the National University of Singapore. “For instance, we could have a multipanel design. And we’re working on a next generation of the material to further improve its intrinsic properties.” Published in Nature Water, the study says the AWHW could last at least a year and shows promise for making safe, sustainable water in places with harsh climates. The researchers believe an array of vertical panels could one day supply water to individual households, especially in remote or off-grid locations. Source: MIT News, Nature This article was generated with some help from AI and reviewed by an editor. Under Section 107 of the Copyright Act 1976, this material is used for the purpose of news reporting. Fair use is a use permitted by copyright statute that might otherwise be infringing.
  • Recent Achievements

    • One Month Later
      Ricky Chan earned a badge
      One Month Later
    • First Post
      leoniDAM earned a badge
      First Post
    • Reacting Well
      Ian_ earned a badge
      Reacting Well
    • One Month Later
      Ian_ earned a badge
      One Month Later
    • Dedicated
      MacDaddyAz earned a badge
      Dedicated
  • Popular Contributors

    1. 1
      +primortal
      505
    2. 2
      ATLien_0
      209
    3. 3
      Michael Scrip
      202
    4. 4
      Xenon
      143
    5. 5
      +FloatingFatMan
      121
  • Tell a friend

    Love Neowin? Tell a friend!