Global Name Not Defined in Python - python

Am new to Python OOP. Please dont be harsh. Here is my code which calculates which is the fastest time of an athlete from a list and displays them. But When Running, I get this error:
z= add.mylist.min()
NameError: global name 'add' is not defined
My Code:
class Athlete:
def add(self):
list=[]
mylist=[]
for i in range(2):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time: ")
list.append(self.name)
mylist.append(self.fastest_time)
print "Names: ",list
print "Fastest times: ",mylist
def display(self):
z= add.mylist.min()
w= add.mylist.index(z)
print "Minimum time: ",z
print "Name of athelte with fastest time: ",list[w]
x = Athlete()
x.add()
x.display()

You need to refer to methods on the instance with the self parameter. In addition, your add() method needs to return the mylist variable it generates, you cannot refer to method local variables as attributes on methods:
def display(self):
mylist = self.add()
z = min(mylist)
w = mylist.index(z)
def add(self):
list=[]
mylist=[]
for i in range(2):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time: ")
list.append(self.name)
mylist.append(self.fastest_time)
print "Names: ",list
print "Fastest times: ",mylist
return mylist
That is what self is for, as a reference point to find instance attributes and other methods on the same object.
You may want to rename list to something that does not shadow the built-in type.

Martijn has already answered your question, so here are some remarks and code style tips:
New-style classes derive from object
You have both athlete names and their times, those belong together as key-value pairs in a dictionary instead of two separate lists
Don't use print statements inside class methods, a class method should return an object that you then can print
what if you have more then 2 athletes for which you want to enter the time? If you make the number of athletes an argument of your function, you can add a variable number of athlethes
give descriptive variable names (not mylist) and don't use names of builtin functions (like list) as variable name
variables that you want to use throughout your class can be initalized in an __init__method.
For printing, use the format function instead of using commas
use if __name__ == '__main__' so that your Python file can act as either reusable modules or as standalone program
Taking these into account, I would rewrite your code to something like this:
from collections import defaultdict
class Athlete(object): # see (1)
def __init__(self): # see (6)
self.athlete_times = defaultdict(str) # see (2)
def add_athletes_and_times(self, n): # see (4)
for i in range(n):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time (in seconds): ")
self.athlete_times[self.fastest_time] = self.name
def get_fastest_time(self):
return min(self.athlete_times) # see (3)
if __name__ == '__main__': # see (8)
x = Athlete()
x.add_athletes_and_times(2)
for fast_time in x.athlete_times:
print "The fastest time of athlete {0} is {1} seconds.".format(
x.athlete_times[fast_time], fast_time) # see (7)
fastest_time = x.get_fastest_time()
print "The overall fastest time is: {0} seconds for athlete {1}.".format(
fastest_time, x.athlete_times[fastest_time])

Related

How to use a method object (which is in the class) outside the class?

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

Defining "add" function in a class

I'm writing my own code language in Python (called Bean), and I want the math functions to have the syntax:
print math.add(3+7)
==>10
print math.mul(4*8)
==>32
and so on. So far my code is:
bean_version = "1.0"
console = []
print "Running Bean v%s" % bean_version
#Math Function
class math(object):
def __init__(self, add, sub, mul, div):
self.add = add
self.sub = sub
self.mul = mul
self.div = div
def add(self):
print self.add
math = math(1,0,0,0)
print math.add()
But this will return an error, saying that TypeError: 'int' object is not callable. I can change the "add" function to a different name and it will work, but I would like to use "add" as the name.
Thanks (This is Python 2.7.10 by the way)
An object can't have two properties with the same name. So if you have a property called add that holds a number, it can't also have a method called add, because methods are just properties that happen to hold functions. When you do:
this.add = add
you're replacing the method with that number. So you need to use different names.
You say you want to be able to call math.Add(). But the method you defined is add. It should be:
def Add():
print this.add
This doesn't conflict with the add property that holds the number, since names are case-sensitive.
If you don't want to change the name of the add function, you can just change self.add. These two adds are conflicting with each other. You will not get any error if you run this:
bean_version = "1.0"
console = []
print "Running Bean v%s" % bean_version
#Math Function
class math(object):
def __init__(self, add, sub, mul, div):
self.adds = add
self.sub = sub
self.mul = mul
self.div = div
def add(self):
print self.adds
math = math(1,0,0,0)
print math.add()

Python Accessing Dict That Has Defualt Values That Have Been Updated

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.

Class does not seem to be Global in python

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.

problems writing address book program in python

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):

Categories

Resources