Why is my instance counter display 0 in this Python code?
I made a simple code to demonstrate and understand classes - however when I run this, my lists show that they are empty, containing "None" values instead of the strings that the user enters as names.
#Static methods do not require the object to be initiated. Can be remotely accessed from outside the function .
#Counting critters and remote access.
class Orc (object):
total = 0
def get_score (self):
print "The number of orcs the orc factory has made is",Orc.total
def开发者_Go百科 __init__ (self):
Orc.total += 1
name = raw_input ("I am a critter by the name of:\n")
#Creating 10 Orcs
list = []
for i in range (4): list[i] = list.append(Orc.get_score(Orc()))
print "You have created 4 Orcs!" print "The name of your first orc is",list[0] print "The name of your fourth orc is", list[3]
There are a few errors in your code. First in the way you use lists. Second, in the way you call methods on your objects. The combination of errors explains why you have a list of None
at the end.
List name
list = []
Don't name a list list
. It is already the name of, well..., the list class, i.e. in Python you can do my_list = []
or my_list = list()
with the exact same effect.
You want to call your list something meaningful, like orc_list
List Insertion
for i in range (4):
orc_list[i] = orc_list.append(...)
orc_list.append
does what it says: it appends an element to the given list. However, it does not return anything. So what your code is doing is
- taking an empty list
- setting
i
to 0 - inserting what you pass to
append
at the end of the list - inserting
None
at indexi
and thus overriding what you did in 3. - incrementing
i
- going back to 3.
You want to simply use orc_list.append(...)
Method Call
Orc.get_score(Orc())
I imagine you are getting confused by the self
argument. In a class, Python will automatically pass the instance you are working on as the self
argument. You don't need to provide that argument.
You want to write
Orc().get_score()
This creates an Orc
object, and then calls get_score
on it. Python 'injects' the Orc
instance you have created into get_score
for you.
Method Return
We're now down to
orc_list.append(Orc().get_score())
which is equivalent to
score = Orc().get_score()
orc_list.append(score)
The problem is that there is no return
statement in get_score
. This means that python will return None
when you call that method. Which means that you are appending None
to your list.
You want to have
def get_score(self):
print "The number of orcs the orc factory has made is", Orc.total
return Orc.total
Static behaviour
If you really wanted to have a method not bound to an instance of the Orc
class, you could use either a class method or a static method.
In your case, you do not need to do anything to the class object, so your choice would be to use a static method.
You would declare
@staticmethod
def get_score():
print "The number of orcs the orc factory has made is", Orc.total
You would then call that method using Orc.get_score()
To define a class method in Python, use classethod
decorator and call the first parameter cls
class Orc(object):
total = 0
@classmethod # this will make the method a class method
def get_score (cls): # convention is then to call the 1st param 'cls'
print "The number of orcs the orc factory has made is", cls.total
def __init__ (self):
Orc.total += 1
# use self is you want' to register a name
# however putting a raw_input in an __init__ is NOT recommanded
# you should pass name as a parameter
# and call the raw_input in the for loop
self.name = raw_input ("I am a critter by the name of:\n")
orcs = [] # don't call your lists 'list' because `list` is standard Python function
for i in range(4): # put this on two lines for clarity or use a comprehension list
orcs.append(Orc())
print "You have created 4 Orcs!"
print "The name of your first orc is", orcs[0].name # if you don't use `name`, you will see the reference of the object
print "The name of your fourth orc is", orcs[3].name
A cleaner version (something you should aim for):
class Orc(object):
total = 0
@classmethod #
def get_instances_count(cls):
"""
Return the number or orcs that have been instanciated
"""
# ^ Put some documentation below your method
# these are called "docstring" and are detected by Python
# you should return values in method rather than print
# there are rare cases when you do want print, but when you'll
# encounter them, you won't need me to correct your code anymore
return cls.total
def __init__ (self, name):
Orc.total += 1
self.name = name # we get the name as a parameter
l = []
for i in range(4): # put this on two lines for clarity or use a comprehension list
orc = Orc(raw_input("Enter a name:\n"))
l.append(orc)
print "You have created %s Orcs!" % Orc.get_instances_count()
print "The name of your first orc is", l[0].name #
print "The name of your fourth orc is", l[3].name
Now the more Pythonic version (something you should be able to do once used to Python):
class Orc(object):
total = 0
# you don't need accessors in Python: most things are public anyway
# and you got property
def __init__ (self, name):
Orc.total += 1
self.name = name # we get the name as a parameter
def __str__(self):
# this will be call when printing an orc
return self.name
# list comprehension are quick and clean ways to create lists
# give a real name to your list
orcs = [Orc(raw_input("Enter a name:\n")) for i in range(4)]
# using parenthesis for `print` is a good habit to take with then incoming Python 3
print("You have created %s Orcs!" % Orc.total)
for i, orc in enumerate(orcs):
print("Orc #%s is %s" % (i, orc))
list.append
returns a None
value, so it essentially never makes sense to assign its result to anything. You call append
for the side-effects, i.e., to have it put a value at the end of the list. Like this:
for i in range (4):
list.append(Orc.get_score(Orc()))
I don't think the Orc.get_score(Orc())
is what you want, either: it also returns None
instead of a score and the method call is technically correct but unlikely to be what you really intend.
Why should there be something in your list?
you do:
list.append(Orc.get_score(Orc())
which is equivalent to:
item_to_add = Orc.get_score(Orc())
list.append(item_to_add)
Your method Orc.get_score
has no return statement, so it returns None
. therefore, item_to_add will be None, and None will be appended to your list.
As a side note: python is not java. Dont use classes just to use classes. Use classes, when you want to follow OO-Pradigma, i.e. sending messages to objects.
精彩评论