Why is my instance counter display 0 in this Python code? - python

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 __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 index i 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.

Related

How do you multiply values within a class in python?

class bread:
def __init__(self,grain,cost,number):
self.grain=(grain)
self.cost=int(cost)
self.number=int(number)
def price(self):
p=self.cost*self.number
print(p)
apple=bread("wholemeal",int(2),int(12))
print(apple.grain,apple.cost,apple.number)
print (apple.price)
After I enter this block of code I should expect to see 24, but instead I get:
bound method bread.price of <main.bread object at 0x05CC7430>>
I am new to oop and starting to experiment but I can't find a solution.
You need to call price:
apple.price()
However, variable attribute behavior with methods can be achieved using property:
class bread:
def __init__(self,grain,cost,number):
self.grain=grain
self.cost=cost
self.number=number
#property
def price(self):
return self.cost*self.number
apple=bread("wholemeal",2, 12)
print(apple.price)
In this case you don't seem to want to deal with a class object, but just want to get the output. This you can do like so:
class bread:
def __init__(self, grain, cost, number):
self.grain = (grain)
self.cost = int(cost)
self.number = int(number)
return self.price()
def price(self):
p = self.cost * self.number
print("%s : %d" % (self.grain, p))
bread("wholemeal", 2, 12)
As a beginner you should not worry too much about things like property but keep it as simple (and verbose) as possible. Also because you're making the input for the grain type, I'm guessing you want to print that out together with the value.
To unpack the changes I made to your code as an example for some basic coding practices:
note the spacing between functions
note the spacing between individual items
note how the output is produced with print()
Once all this is done, all we have to do is make the call we would otherwise have to make ourselves everytime, inside __init__. Good luck, and have fun learning python!
When you print the function at the end, you actually need to call the function. Currently you are just getting the instance of the method within the object. But you should be using parenthesis () to call the function when you print it. You also don't need to print the function call to get 24 since you are already printing the output of number and cost within your function. But if you do want to print the function, you can use a return value within your function. Here is an example below:
class bread(object):
def __init__(self, grain, cost, number):
self.grain = grain
self.cost = cost
self.number = number
def price(self):
price = self.cost * self.number
return price
apple=bread("wholemeal", 2, 12)
print(apple.price())
Notice that at the end of the code We actually called the function () when printing it. You will then print the return value of the function. If you wanted to simply print the value within the function, you could call the function at the bottom of the code without printing it like this:
apple.price()
and then choose to put the print statement within the price method. Your output from the code above it 24:
24

Python - Using list of strings as class data member. When strings contain variables, variables don't update

Is there a way to change variables within lists within classes after the class instance has been initialized? (Sorry, sounds more complicated than it is!)
I'm writing a game and storing all of my display text as array elements in instances of a "Text" class. I wrote the following example program to test what I'm trying to do:
#****************************************#
#INITIALIZE CLASS (to hold text component)
#****************************************#
class Text:
def __init__(self, array, maxIndex):
#list of text
self.list = array
#number of items in list
self.max = maxIndex
#set global variable to 7
globalv = 7
#****************************************#
#INITIALIZE VARIABLE-ENHANCED TEXT
#necessary because variables inside class
#data member arrays seem to have a local
#scope, and can't be changed after they
#are initialized
#****************************************#
varLine = Text(["This line contains globalv, which holds: {}".format(globalv)], 0)
print varLine.list[varLine.max]
#prints 7
#CHANGE VALUE OF globalv:
print "Directly accessing globalv: {}".format(globalv)
#prints 7
print "\nUpdate value of globalv to 9"
globalv = 9
print "Directly accessing globalv: {}".format(globalv)
#prints 9
#Try to change and re-print variable
#doesn't work, despite the fact that "global" has changed outside of the class
print "\nfirst try:"
#call print function on globalv directly:
print "Directly accessing globalv: {}".format(globalv)
#prints 9
#print it from the class:
print "Printing from class:"
print varLine.list[varLine.max])
#prints 7
#Change variable by re-initializing class
print "\nsecond try:"
varLine = Text(["This line contains globalv, which holds: {}".format(globalv)], 0)
#call print function on globalv directly:
print "Directly accessing globalv: {}".format(globalv)
#prints 9
#print it from the class:
print "Printing from class:"
print varLine.list[varLine.max])
#prints 9
When you create that string you are concatinating the current value of globalv into a string. Changing globalv after that string been created has no effect on the value of the string. You can make setter and print methods to accomplish this:
class Text:
def __init__(self, strList, valueList, maxIndex):
#list of text/values
self.strList = strList
self.valueList = valueList
#number of items in list
self.max = maxIndex
def printStrAtIndex(self, idx):
print(self.strList[idx] + str(self.valueList[idx]))
def setValAtIndex(self, val, idx):
self.valueList[idx] = val
return self
# add new str value pair to the the class
def addStrAndValue(self, newStr, newValue):
self.strList.append(newStr)
self.valueList.append(newValue)
self.max = len(self.valueList)-1
Then just call it like this:
varLine = Text(["This line is tied to the value: "], [7], 0)
varLine.printStrAtIndex(0)
varLine.setValAtIndex(9,0)
varLine.printStrAtIndex(0)
Answer is easy.
str.format()
Function returns copy of string with intrerpolated values.
So Your Class contains :
vaeLine.list = ["Copy of formating string with resolved value"]
When You change global var to soemthing this string isn't reevaluated
And this string copy is immutable so Your class is holding array which is muteable but its holding just an already resolved string with value 7. So changing global doesnt affect this stirng.
The code is working correctly. I'm not sure what you're expecting.
You convert globalv to text and store it in an object's text. When you come back later, that text string is just as you left it. Are you expecting it to magically change because you changed the value of globalv? This is somewhat like taking a photograph of yourself, changing clothes, and expecting the photo to change to match your new outfit. Variables don't work that way.
Perhaps what you need is a two-step approach:
Create an attribute to hold the value, such as self.value
Write a method to display an object's attribute; within that method, acces the current value of self.value, using that in the display string that you build.
Does that help?

FastQ programming error

So I'm trying to parse a FastQ sequence, but I'm a beginner to Python, and I'm a little confused as to why my code isn't working. This is what the program is supposed to carry out:
if I enter the FASTQ seqname line...
#EAS139:136:FC706VJ:2:2104:15343:197393
...then the program should output:
Instrument = EAS139
Run ID = 136
Flow Cell ID = FC706VJ
Flow Cell Lane = 2
Tile Number = 2104
X-coord = 15343
Y-coord = 197393
Here's my unfinished code thus far:
class fastq:
def __init__(self,str):
self.str = inStr.replace ('#',' ').split (':')
def lists (self,parameters):
self.parameters = ("Instrument","Run ID","Flow Cell ID","Flow Cell Lane","Tile Number","X-coordinates","y-coordinates")
def zip (self,myZip,zippedTuple):
self.Zip = zip(self.parameters,self.transform)
self.zippedTuple = tuple(myZip)
print (tuple(myZip))
def main():
seq = input('Enter FastQ sequence:')
new_fastq = fastq(str)
new_fastq.lists()
new_fastq.zip()
main()
The reason that your code isn't working is that it's more-or-less entirely wrong. To address your errors in the order we reach them when trying to run the program:
main:
new_fastq = fastq(str) does not pass the seq we just input, it passes the built-in string type;
__init__:
Calling the argument to fastq.__init__ str is a bad idea as it masks the very built-in we just tried to pass to it;
But whatever you call it, be consistent between the function definition and what is inside it - where do you think inStr is coming from?
lists:
Why is this separate to and not even called by __init__?
Why don't you pass any arguments?
What is the argument parameters even for?
zip:
Rather than define a method to print the object, it is more Pythonic to define fastq.__str__ that returns a string representation. Then you can print(str(new_fastq)). That being said;
Again, you mask a built-in. On this occasion, it's more of a problem because you actually try to use the built-in inside the method that masks it. Call it something else;
Again, you put unnecessary arguments in the definition, then don't bother to pass them anyway;
What is self.transform supposed to be? It is never mentioned anywhere else. Do you mean self.str (which, again, should be called something else, for reasons of masking a built-in and not actually being a string)?
myZip is one of the arguments you never passed, and I think you actually want self.Zip; but
Why would you create x = tuple(y) then on the next line print(tuple(y))? print(x)!
Addressing those points, plus some bonus PEP-008 tidying:
class FastQ:
def __init__(self, seq):
self.elements = seq.replace ('#',' ').split (':')
self.parameters = ("Instrument", "Run ID", "Flow Cell ID",
"Flow Cell Lane", "Tile Number",
"X-coordinates", "y-coordinates")
def __str__(self):
"""A rough idea to get you started."""
return "\n".join(map(str, zip(self.parameters, self.elements)))
def main():
seq = input('Enter FastQ sequence: ')
new_fastq = FastQ(seq)
print(str(new_fastq))
main()

How do I automatically pass arguments to a function on certain objects

I am trying to make a text based game using Python. I set up a radar() function but currently the only way to use it is if the player types in arguments directly to the console. I want the program to detect which vehicle the player is piloting and pass whatever attributes of that vehicle need to be passed automatically without the player having to type them.
For example
Instead of the player having to type in
'a.radar([100,100,100], 100)' in order to use the radar() function I want the player to only need to type in 'radar', and all other parameters to be passed automatically. How can I make this happen? Should I restructure this code entirely?
My code:
class Mobilesuits:
#class global variables/methods here
instances = [] #grid cords here
def __init__(self,armor,speed,name,description,cockpit_description,\
radar_range, coordinates):
Mobilesuits.instances.append(self)
self.armor=armor
self.speed=speed
self.name=name
self.description=description
self.cockpit_description=cockpit_description
self.radar_range=radar_range
self.coordinates=coordinates
def radar(self, coordinates, radar_range):
for i in range(len(a.instances)):
cordcheck=a.instances[i].coordinates
if cordcheck == coordinates:
pass
elif (abs(cordcheck[0]-coordinates[0]) <= radar_range) and \
(abs(cordcheck[1]-coordinates[1]) <= radar_range) and \
(abs(cordcheck[2]-coordinates[2]) <= radar_range):
print("%s detected at %s ") %(a.instances[i].description, a.instances[i].coordinates)
a=Mobilesuits(100,100,"Leo","leo desc","dockpit desc",100,[100,100,100])
b=Mobilesuits(100,100,"Leo","leo desc","dockpit desc",100,[300,100,100])
c=Mobilesuits(100,100,"Leo","leo desc","dockpit desc",100,[100,150,100])
a.radar([100,100,100], 100)
Have your program take input with the raw_input function:
user_input = raw_input()
and then do something based on the input:
if user_input == "some_command":
do_something(appropriate, variables)
For example,
if user_input == "radar":
a.radar([100,100,100], 100)
You might also want to change the way the radar method takes arguments. It looks like at least one of the coordinates or the radar_range arguments should be coming from the corresponding attributes of self. For example, if a mobile suit's radar should automatically use the mobile suit's own coordinates and radar range, you could write the method as follows:
def can_detect(self, other):
for own_coord, other_coord in zip(self.coordinates, other.coordinates):
if abs(own_coord - other_coord) > self.radar_range:
return False
return True
def radar(self):
for other in Mobilesuits.instances:
if other is not self and self.can_detect(other):
print "%s detected at %s" % (other.description, other.coordinates)
Do it like builtins do.
Look, str() function is just specialized call to __str__ function. object class has default __str__, and if you're not using p3k, str() has some logic for objects without __str__.
In the end, str() builtin MAY look like this (conceptually, implementation is probably quite different):
def str(obj):
try:
return obj.__str__()
except AttributeError:
return default_behaviour(obj)
You can do something alike.
You'll need function which will return user object (say there are 3 players in the game: A, B and C, where A is controlled by user; you'll need function get_user_player() which shall return A instance.
Then, you need to implement your argumentless radar function:
def radar():
return get_user_player().radar()
Now call to radar() will result in automatic finding of user controlled instance and calling radar on it.

Re-evaluating a function to get a new random value in python

here is the code that I am having a problem with(simplified to make it clearer). It is for a text based game just to help learn things.
class Character(object):
def __init__(self):
self.level = 5
self.moveset = [None,None,None,None]
def movesetleveling(self):
if self.level > 4:
self.moveset[0] = Punch(self.level)
def punch(level):
damagedealt = random.randint(0,5)**level
return damagedealt
I would like to know how I can make self.moveset[0] = Punch() rather than being equal to the output of Punch() in this block of code. So that everytime i run it in a while loop it will re-evaluate the output of Punch() rather than evaluating Punch() once and assigning that to the 0th index of self.moveset[0].
You could assign a function to self.moveset[0] instead of its result (using functools.partial()):
from functools import partial
self.moveset[0] = partial(punch, self.level)
Then later, in your while loop, just call it:
while True:
new_punch_every_time = self.moveset[0]() #note: parentheses
self.moveset[0]() calls punch function with level parameter set to self.level (its value at the time of partial call).
It works because functions, methods are first class citizens in Python. You can pass them as parameters to other functions, return from functions, bind to a different name, append to a list, etc.

Categories

Resources