So I have this class:
class hero():
def __init__(self, name="Jimmy", prof="Warrior", weapon="Sword"):
"""Constructor for hero"""
self.name = name
self.prof = prof
self.weapon = weapon
self.herodict = {
"Name": self.name,
"Class": self.prof,
"Weapon": self.weapon
}
self.herotext = {
"Welcome": "Greetings, hero. What is thine name? ",
"AskClass": "A fine name, {Name}. What is your class? ",
"AskWeapon": "A {Class}, hmm? What shalt thy weapon be? ",
}
def setHeroDicts(self, textkey, herokey):
n = raw_input(self.herotext[textkey].format(**self.herodict))
if n == "":
n = self.herodict[herokey]
self.herodict[herokey] = n
#print self.herodict[herokey]
def heroMake(self):
h = hero()
h.setHeroDicts("Welcome", "Name")
h.setHeroDicts("AskClass", "Class")
h.setHeroDicts("AskWeapon", "Weapon")
And in another class I have this executing
def Someclass(self):
h = hero()
print h.herodict["Class"]
h.heroMake()
print h.getClass()
if "Mage" in h.herodict["Class"]:
print "OMG MAGE"
elif "Warrior" in h.herodict["Class"]:
print "Warrior!"
else:
print "NONE"
So if I input nothing each time, it will result in a blank user input, and give the default values. But if I put an input, then it will change the herodict values to what I customize. My problem is, if I try and access those updated values in Someclass it only gives me the default values instead of the new ones. How do I go about accessing the updated values?
The main issue with your class is that you are creating a new object within heromake instead of using the existing one. You can fix this by replacing h with self (so that each time you are calling setHeroDicts on the object):
def heromake(self):
self.setHeroDicts("Welcome", "Name")
self.setHeroDicts("AskClass", "Class")
self.setHeroDicts("AskWeapon", "Weapon")
The first argument to a method is always set to the instance itself, so if you want to interact with the instance or mutate it, you need to use it directly. When you do h = hero() in your original code, you create a whole new hero object, manipulate it and then it disappears when control passes back to your function.
A few other notes: you should name your classes with CamelCase, so it's easier to tell they are classes (e.g., you should really have class Hero) and in python 2, you need to make your classes descend from object (so class Hero(object)). Finally, you are duplicating nearly the entire point of having classes with your herodict, you should consider accessing the attributes of the object directly, instead of having the intermediary herodict (e.g., instead of doing h.herodict["Class"] you could do h.prof directly.
Related
If I have a Numeric Property in two of my screens that count how many times a person clicked the correct icon and I want to print it in a separate class how would I do this? I have tried using the print() function and using print(StringProperty(str())) but I dont get a number value printed. When I print the correct_counter in VerifyAA() and VerifyBB() the correct value is printed.
class A(Screen):
correct_counter1 = NumericProperty(0)
def verifyAA(self, *args):
if self.AA == V.Check1 or self.AA == V.Check2 or self.AA == V.Check3:
print("You got it!!!")
self.correct_counter1 = self.correct_counter1 + 1
print(self.correct_counter1)
self.ids.aa.disabled = True
class B(Screen):
correct_counter2 = NumericProperty(0)
def verifyBB(self, *args):
if self.BB == VV.Check1 or self.BB == VV.Check2 or self.BB == VV.Check3:
print("You got it!!!")
self.correct_counter2 = self.correct_counter2 + 1
print(self.correct_counter2)
self.ids.bb.disabled = True
class Answers(Screen):
print(A.correct_counter1)
print(StringProperty(str(B.correct_counter2)))
This is what gets printed respectively:
<NumericProperty name=correct_counter>
<StringProperty name=>
You need to understand the distinction between the definition of a class and an instance of a class. When you print A.correct_counter1 you print the NumericProperty object itself, defined at class level. That's the only sensible result - it wouldn't make sense for it to print the value of the property, because it doesn't have a value. For instance, if you wrote instance1 = A(correct_counter1=1); instance2 = A(correct_counter1=20) what value would you have expected print(A.correct_counter1) to print? The answer has to be neither, the value of the property is defined in each case for the class instance, not the class itself.
The correct solution is that you must print the value of the property via an instance of your class. For instance, if you write instance = A(); print(instance.correct_counter1) you will print a number like you expect. The best way to do this depends on the structure of your program and the relationship between the classes. Your example isn't a runnable program so it isn't possible to make a specific suggestion. If you have an actual example where you want to do this but can't work out how, post that as a new question.
I have a method object with assigned value from user's input inside a class. The problem is i can't use the method object maxcount_inventory = int(input("How many Inventories: ")) outside the class. The error says "method' object cannot be interpreted as an integer"
class CLASS_INVENTORY:
maxcount_inventory = int(input("How many Inventories: "))
inventory_name = []
def __init__(Function_Inventory):
for count_inventory in range(Function_Inventory.maxcount_inventory):
add_inventory = str(input("Enter Inventory #%d: " % (count_inventory+1)))
Function_Inventory.inventory_name.append(add_inventory)
def Return_Inventory(Function_Inventory):
return Function_Inventory.inventory_name
def Return_Maxcount(Function_Inventory):
return maxcount_inventory
maxcount_inventory = CLASS_INVENTORY().Return_Maxcount
Another extra question if I may, how can i access items in the list per index outside the class? I have the code below, but I think it's not working. Haven't found out yet due to my error above.
for count_inventory in range(maxcount_inventory):
class_inv = CLASS_INVENTORY().Return_Inventory[count_inventory]
print(class_inv)
skip()
Here is my full code: https://pastebin.com/crnayXYy
Here you go I've refactored your code.
As #Daniel Roseman mentioned you should be using self rather than Function_Inventory, so I changed that. I also changed the return value of Return_Maxcount to provide a list as you requested.
class CLASS_INVENTORY:
maxcount_inventory = int(input("How many Inventories: "))
inventory_name = []
def __init__(self):
for count_inventory in range(self.maxcount_inventory):
add_inventory = str(input("Enter Inventory #%d: " % (count_inventory+1)))
self.inventory_name.append(add_inventory)
def Return_Inventory(self):
for item in self.inventory_name:
print(item)
def Return_Maxcount(self):
return self.inventory_name
maxcount_inventory = CLASS_INVENTORY()
inventory_list = maxcount_inventory.Return_Maxcount()
maxcount_inventory.Return_Inventory()
You can change the print statement at the bottom and set that equal to a variable to access it outside of the class itself.
In your code just change this:
maxcount_inventory = CLASS_INVENTORY().Return_Maxcount
to this:
maxcount_inventory = CLASS_INVENTORY().Return_Maxcount()
also change the variables in your class to have the self. prefix before them
like self.maxcount_inventory
the reason is you want to call your method , otherwise it will try getting a variable not the method.
you also want to change all your arguments in your functions inside of the class to self
So clearly Im doing something wrong. Im a new python/noob coder so it may be obvious for many of you but Im not sure what to do.
class hero():
"""Lets do some heros shit"""
def __init__(self, name="Jimmy", prof="Warrior", weapon="Sword"):
"""Constructor for hero"""
self.name = name
self.prof = prof
self.weapon = weapon
self.herodict = {
"Name": self.name,
"Class": self.prof,
"Weapon": self.weapon
}
self.herotext = {
"Welcome": "Greetings, hero. What is thine name? ",
"AskClass": "A fine name %s. What is your class? " % self.herodict['Name'],
}
def thingy(self, textkey, herokey):
n = raw_input(self.herotext[textkey])
self.herodict[herokey] = n
if self.herodict[herokey] != "":
print self.herodict[herokey]
else:
self.herodict[herokey] = self.name
print self.herodict[herokey]
def setHeroName(self):
self.thingy("Welcome", 'Name')
def setHeroClass(self):
self.thingy("AskClass", 'Class')
So basically you run this and it sets a bunch of default values. It will ask a name, and you give it user input, and it sets the Name key to the new value of your input. They it is suppose to take that new key:value or name:(userinput) and use it in the next little sentence. But instead its going back and using the default value of 'jimmy'.
What do I need to do?
The line:
"AskClass": "A fine name %s. What is your class? " % self.herodict['Name'],
is executed when you create the class, not when you later print it. When you create the class, self.herodict['Name'] is set to 'Jimmy'.
You'll have to do the interpolation later on, when you actually have a name. Perhaps you need to use callables instead, like lambda objects:
self.herotext = {
"Welcome": lambda self: "Greetings, hero. What is thine name? ",
"AskClass": lambda self: "A fine name %s. What is your class? " % self.herodict['Name'],
}
then call them passing in self later on:
n = raw_input(self.herotext[textkey](self))
I setup a class and it accepts and prints out the variables fine in one if statement.
class npc: #class for creating mooks
def __init__(self, name):
self.name = name
def npc_iq (self,iq):
self.iq = []
def npc_pp (self,pp):
self.pp = []
def npc_melee (self, melee):
self.melee = []
def npc_ct (self, ct):
self.ct = []
It works fine in this if statement
if menu_option == 1:
print "Choose melees for npc"
init_bonus = random.randint(0,2)
char_PP = random.randint(7,15)
char_iq = random.randint(7,15)
npc_Melees = int(raw_input(prompt))
combat_time = math.floor((round_attacks - init_bonus - math.floor(char_PP/2) - math.floor(char_iq/2)) / npc_Melees)
#function for calculating sequence number
print "combat time is"
print combat_time
mook = "mook%s" % counter # adds different mook names to program
mook = npc(mook)
mook.iq = (char_iq)
mook.pp = (char_PP)
mook.melee = (npc_Melees)
mook.ct = (combat_time)
counter += 1
But on this statement it will print out the name in the class but not ct.
elif menu_option ==4:
print "Printing out all mooks"
print
printcount = counter -1
while printcount != 0:
mookprint = "mook%s" % printcount
mookprint = npc(mookprint)
print mookprint.name
print mookprint.ct
print
printcount -= 1
Why would a mookprint have any idea what value ct should be? The constructor for npc initialises a new instance of npc, with the name given as a parameter, but ct is left empty.
When you create an NPC in menu option 1, you do not create a global instance of npc. If you want to refer to a previously created instance of npc, you will need to find some way of storing them. Dictionaries may be a good solution for you. A dictionary is an object that holds mappings between keys and values. If you know the key, then you can find the assosicated value. In this case you would make name the key and the value the npc instances.
eg.
npcsDict = dict()
if menu_option == 1:
# code for intialising a new instance of npc
...
# most, if not all of the initialisation code should be moved to the
# __init__ method for npc
# now store the newly created mook
npcsDict[mook.name] = mook
elif menu_option == 4:
print "Printing out all mooks"
print
for mookName in npcsDict:
print npcsDict[mookName].name
print npcsDict[mookName].ct
print
i dont really understand your problem.
your working example:
mook = npc(mook)
mook.iq = (char_iq)
mook.pp = (char_PP)
mook.melee = (npc_Melees)
mook.ct = (combat_time)
mook.ct is value of (combat_time)
your failing example:
mookprint = npc(mookprint)
print mookprint.name
print mookprint.ct
mookprint.ct's value is nothing because it is never set.
The elif will only be executed if the if has not, so if the elif block runs, ct was never set
I don't think you're understanding how four lines work:
mookprint = "mook%s" % printcount
mookprint = npc(mookprint)
print mookprint.name
print mookprint.ct
Every time this block of code is run, the following things are happending:
You're assigning a string of the form "mook" to the variable mookprint
You're creating a new instance of the npc class. You should note that all of the instances you're creating will be separate from eachother. This new instance will have an attribute with the name that was previously held in the variable mookprint and this instance of npc will be assigned to mookprint.
You're printing the name attribute of the instance of the npc class that you created in the previous step. This works because when this instance was created, the __init__ method of your class was called with the argument name being set to "mook1" or whatever was stored in mookprint at the time.
You're printing the ct attribute of the instance of the npc class that you just created. Since you never set the ct attribute to anything, this will not work how you expected.
If you want to count the number of instances of your npc class, you'll need to create a class attribute. This is a variable whose value is common across all instances of a class. To do so, you'll need to modify your class definition to add an item to this attribute every time you make a new instance of the class. It will look something like this:
class npc: #class for creating mooks
ct = []
def __init__(self, name):
self.name = name
self.ct.append(name)
def get_ct(self):
return len(self.ct)
With the above, the variable ct will be a list that is common to all instances of npc and will grow every time a new npc is created. Then the method get_ct will count how long this list is.
Then you'll need to modify the four lines I mentioned to look like:
mookprint = "mook%s" % printcount
mookprint = npc(mookprint)
print mookprint.name
print mookprint.get_ct()
I think the code above shows how to change your code to work more how you expected it to work. However, it should be noted that you rarely want to create classes where each instance depends on information about the other instances. It is usually a better design to do something like Dunes suggested, storing the instances in a dictionary, or some other data structure, and keeping track of them that way.
I am writing a program to add to and update an address book. Here is my code:
EDITED
import sys
import os
list = []
class bookEntry(dict):
total = 0
def __init__(self):
bookEntry.total += 1
self.d = {}
def __del__(self):
bookEntry.total -= 1
list.remove(self)
class Person(bookEntry):
def __init__(self, n):
self.n = n
print '%s has been created' % (self.n)
def __del__(self):
print '%s has been deleted' % (self.n)
def addnewperson(self, n, e = '', ph = '', note = ''):
self.d['name'] = n
self.d['email'] = e
self.d['phone'] = ph
self.d['note'] = note
list.append()
def updateperson(self):
key = raw_input('What else would you like to add to this person?')
val = raw_input('Please add a value for %s' % (key))
self.d[key] = val
def startup():
aor = raw_input('Hello! Would you like to add an entry or retrieve one?')
if aor == 'add':
info = raw_input('Would you like to add a person or a company?')
if info == 'person':
n = raw_input('Please enter this persons name:')
e = raw_input('Please enter this persons email address:')
ph = raw_input('Please enter this persons phone number:')
note = raw_input('Please add any notes if applicable:')
X = Person(n)
X.addnewperson(n, e, ph, note)
startup()
When I run this code I get the following error:
in addnewperson
self.d['name'] = n
AttributeError: 'Person' object has no attribute 'd'
I have two questions:
UPDATED QUESTIONS
1. why isnt the d object being inherited from bookentry()?
I know this question/code is lengthy but I do not know where to go from here. Any help would be greatly appreciated.
The addnewperson shoud have 'self' as first argument; actually, the name doesn't matter ('self' is just a convention), but the first argument represent the object itself. In your case, it's interpreting n as the "self" and the other 3 as regular arguments.
____del____ must not take arguments besides 'self'.
Edit: BTW I spotted a few other problems in your example, that maybe you're not aware of:
1) d in bookentry is a class member, not an instance member. It's shared by all bookentry's instances. To create an instance member, use:
class bookentry(dict):
def __init__(self,n):
self.d = {}
# rest of your constructor
2) you're trying to access d directly (as you would do in Java, C++ etc), but Python doesn't support that. You must have a 'self' parameter in your methods, and access instance variables through it:
class person(bookentry):
def foo(self,bar):
self.d[bar] = ...
person().foo(bar)
Update: for the last problem, the solution is to call the super constructor (which must be done explicitly in Python):
class Person(bookEntry):
def __init__(self, n):
super(Person, self).__init__()
self.n = n
print '%s has been created' % (self.n)
A brief explanation: for people with background in OO languages without multiple inheritance, it feels natural to expect the super type constructor to be called implicitly, automatically choosing the most suitable one if no one is mentioned explicitly. However, things get messy when a class can inherit from two or more at the same time, for this reason Python requires the programmer to make the choices himself: which superclass constructor to call first? Or at all?
The behavior of constructors (and destructors) can vary wildly from language to language. If you have further questions about the life cycle of Python objects, a good place to start would be here, here and here.
why isnt the d object being inherited from bookentry()?
That's because __init__ of the bookEntry is not called in the __init__ of the Person:
super(Person, self).__init__()
BTW, why inherit from dict if its functionality is not used? It's better to remove it and inherit from object instead (also class names are usually CamelCased):
class BookEntry(object):