'NoneType' object has no attribute - python

I'm getting an error about 'NoneType' object has no attribute.... How do I resolve it?
def fight(self, pMonstername):
print ("The fight begin")
MonInList = self.monsterSearch(pMonstername)
#at first I have the method "Fight" where i build a temp variable MonInList
#which I declare with the help of the methode "monsterSearch"
def monsterSearch(self, pMonstername):
for m in self.monsterList:
if m.name == pMonstername:
return m
#in this method I go through step by step through the monsterList, in which
#are objects of type Monster are stored and pick out those monster which has
#the same name as those I search for and this object should be returned
if self.player.getStrength() > MonInListe.getStrength:
#later I want to compare the strength of the player and the Monster, which i
#declared before, but then there is the error:
AttributeError: 'NoneType' object has no attribute 'getStrength'

The Short Answer
The short answer to this question is that the error AttributeError: 'NoneType' object has no attribute 'getStrength' suggests that you have self.player = None in the __init__() of the class that contains your conditional if self.player.getStrength() > ..., but it wasn't properly updated to be something else (perhaps an instance of class Player?) before the conditional.
There are some other problems and errors that this will trigger, but this is the place where I would start to try to debug things.
The Long Answer
Another important thing to watch out for is that just because you've included the method in your class doesn't mean it will automatically run. The fact that you are running into the error that you described, and not one of the other errors I think I see in your code, suggests that the methods are either not being called in the correct order to be properly used in your comparison, or are not called at all. This is why I think the Player class was simply not being called correctly.
To give an example, see the code block below. It is a variation of what was provided in the question, and if it is run it will reproduce the problem. First the classes and methods:
# The post author mentioned there objects of the type Monster
# stored in a list in the main class.
# Using the main monster characters from Monsters Inc,
# below are hastily constructed classes to attempt to reproduce the issue.
class Sully(object):
def __init__(self):
self.name = "James P. Sullivan"
self.getStrength = 10
class Player(object):
def getStrength(self):
return 100
class SomeClass(object):
def __init__(self):
self.monsterList = [Sully]
self.player = None
def fight(self, pMonstername):
#at first I have the method "Fight" where i build a temp variable MonInList
#which I declare with the help of the methode "monsterSearch"
print ("The fight begin")
MonInList = self.monsterSearch(pMonstername)
def monsterSearch(self, pMonstername):
#in this method I go through step by step through the monsterList, in which
#are objects of type Monster are stored and pick out those monster which has
#the same name as those I search for and this object should be returned
for m in self.monsterList:
if m.name == pMonstername:
return m
def compareStrength(self):
#later I want to compare the strength of the player and the Monster, which i
#declared before, but then there is the error:
if self.player.getStrength() > MonInListe.getStrength:
print("Success!")
# AttributeError: 'NoneType' object has no attribute 'getStrength'
Next, let's create an instance of SomeClass and then run the compareStrength method:
s = SomeClass()
s.compareStrength()
The result is this error, the stack provided in full:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-71-bfa22232a4a7> in <module>()
1 s = SomeClass()
----> 2 s.compareStrength()
<ipython-input-70-3a4fe2cd3c3c> in compareStrength(self)
42 #later I want to compare the strength of the player and the Monster, which i
43 #declared before, but then there is the error:
---> 44 if self.player.getStrength() > MonInListe.getStrength:
45 print("Success!")
46 # AttributeError: 'NoneType' object has no attribute 'getStrength'
AttributeError: 'NoneType' object has no attribute 'getStrength'
What's interesting about this is that this should NOT have been the first error that was triggered. I would have expected this error instead:
The fight begin
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-79-5009b509291a> in <module>()
1 s = SomeClass()
----> 2 s.fight("James P. Sullivan")
3 s.compareStrength()
<ipython-input-77-13d18f4abe98> in fight(self, pMonstername)
29 #which I declare with the help of the methode "monsterSearch"
30 print ("The fight begin")
---> 31 MonInList = self.monsterSearch(pMonstername)
32
33 def monsterSearch(self, pMonstername):
<ipython-input-77-13d18f4abe98> in monsterSearch(self, pMonstername)
36 #the same name as those I search for and this object should be returned
37 for m in self.monsterList:
---> 38 if m.name == pMonstername:
39 return m
40
AttributeError: type object 'Sully' has no attribute 'name'
...which would be caused by running this code:
s = SomeClass()
s.fight("James P. Sullivan")
s.compareStrength()
I think s.fight() should have been called and triggered this error because otherwise the MonInList would not be correct when we run compareStrength(). It's for this reason that I think simply reviewing the order in which the methods are being called will fix the main issue in the question, which is why I included it here (even though it seems tangential).
Oh, and by the way, the fix for the latest issue described would be to change the line if m.name == pMonstername: to if m().name == pMonstername:
Hope that helps!

Ok, so it seems that your object 'MonInListe' has not been instantiated before being used. It then gets to be 'None' and effectively has no attribute.
You should check elsewhere in your code (not in the shown part of it here) for the correct instantiation of this object 'MonInListe'.
The origin of the error you are encountering is definitively not contained in the part of the code you expose here.

Related

How to update variables passed between classes?

I'm trying to pass variables between different classes. In order to accompish this task, I have created an info class (here called 'declaration') so that the code reads:
class declaration():
def __init__(self):
self.info1 = 999
self.info2 = 'something_else'
print ('At declaration ')
class controller():
def __init__(self):
instance = declaration()
print ('Initial number ',instance.info1, instance.info2)
modifier(declaration)
print ('MIDDLE ',instance.info1,declaration.info1)
instance = declaration()
print ('Final number ',instance.info1)
class modifier():
def __init__(self,aux):
print ('MODIFIER')
self.info=aux
self.info.info1=55555
controller()
The output is:
At declaration
Initial number 999
something else
MODIFIER
MIDDLE 999 55555
At declaration
Final number 999
However, I'm not really sure about some of the inners of the code. I have one major question and a minor one. My main question is that when the class 'modifier' is modified according to:
class modifier():
def __init__(self,aux):
self.info=aux
print ('MODIFIER',self.info.info1)
self.info.info1=55555
it produces the error AttributeError: type object 'declaration' has no attribute 'info1' [Flipping the last 2 lines fixes the error]. It's confusing (at least to me) whether the class attributes are not passed or they have to be reinitialized.
The second question is how to update instance once its class has been updated. The second call to instance = declaration() seems to accomplish nothing.
Quick side note: Yes I do realise, I just want to say please try to follow the PEP8 python guide as it makes your code look cooler (and easier to read) and all the cool kids use it.
There are a few things wrong with your code, calling modifier(declaration) actually makes the aux parameter an uninitilized class, you want to call modifier(instance) as the init function has already been ran.
Also it would be easier to drop the self.info = aux as you can just call aux.info1 and it looks cleaner and is actually faster (Because you are calling one less Fast Store command in bytecode).
Lastly at print ('MIDDLE ',instance.info1,declaration.info1) you again parse declaration uninitilized therefore you get the error AttributeError: type object 'declaration' has no attribute 'info1', to fix this simply put declaration().info1 as that calls the init function (it is the same as saying declaration.__init__().info1).
So finally you get:
class declaration():
def __init__(self):
self.info1 = 999
self.info2 = 'something_else'
print ('At declaration ')
class controller():
def __init__(self):
instance = declaration()
print ('Initial number ', instance.info1, instance.info2)
modifier(instance)
print ('MIDDLE ', instance.info1, declaration().info1)
instance = declaration()
print ('Final number ',instance.info1)
class modifier():
def __init__(self, aux):
print ('MODIFIER')
aux.info1 = 55555
controller()
Hope this helped.

AttributeError: 'NoneType' object has no attribute 'print_Toy'

I am having a very simple code of python, wherein I am creating an object array in the constructor, But whenever I try calling a display function to see all the objects in the Object Array, it returns this NoneType exception.
Class called Toy is the actual object class, which is shown below:
class Toy:
__name=None
__cost=None
def __init__(self,name,cost):
self.__name=name
self.__cost=cost
def get_Name(self):
return self.__name
def get_Cost(self):
return self.__cost
def print_Toy(self):
print(" Name of the toy: ",self.__name)
print(" Cost of the toy: ",self.__cost)
The below-shown class Toy_Bag contains the object array, which I am initializing in the constructor.
from Toy import Toy
class Toy_Bag:
__toys=[None]
def __init__(self, no_of_toys):
self.__create_Toy_bag(no_of_toys)
def __create_Toy_bag(self, no_of_toys):
name,cost= None,0
for toy in range(0, no_of_toys):
print("\n Enter the name of the toy: ",end="")
name=input()
print("\n Enter the cost of the toy: ",end="")
cost=int(input())
toy=Toy(name,cost)
self.__toys.append(toy)
self.print_Toy_Bag()
def print_Toy_Bag(self):
for toy in self.__toys:
toy.print_Toy()
Traceback (most recent call last):
File "Main.py", line 9, in <module>
toy_bag=Toy_Bag(3)
File "C:\Users\SONY\Desktop\Python Scripts\Tools\Toy_Bag.py", line 8, in __init__
self.__create_Toy_bag(no_of_toys)
File "C:\Users\SONY\Desktop\Python Scripts\Tools\Toy_Bag.py", line 19, in __create_Toy_bag
self.print_Toy_Bag()
File "C:\Users\SONY\Desktop\Python Scripts\Tools\Toy_Bag.py", line 23, in print_Toy_Bag
toy.print_Toy()
AttributeError: 'NoneType' object has no attribute 'print_Toy'
C:\Users\SONY\Desktop\Python Scripts\Tools>
Any help is highly appreciated.
You are initializing your list with one element of None right here:
class Toy_Bag:
__toys=[None]
then you add more toys inside def __create_Toy_bag(self, no_of_toys) - will be at position 1 to n inside your list. The first stays None.
If you print your __toys you call a method of your Toy-class with this first None.
Change it to
__toys=[]
so
def print_Toy_Bag(self):
for toy in self.__toys: # first element is no longer None
toy.print_Toy()
does no longer get the first element as None.
You might want to give How to debug small programs (#1) a read -it helps you debug your own programs. If you are interested in how to name stuff "correctly": PEP-008: Style Guide is a great read as well (spacing, private members and a lot of other stuff covered in it).

Referencing an object's attribute through an argument [duplicate]

This question already has answers here:
Changing a string to variable [duplicate]
(2 answers)
Closed 4 years ago.
I am trying to create a function that calls an attribute determined by what argument is passed.
class room:
def __init__(self, length, bredth, depth):
self.length = length
self.bredth = bredth
self.depth = depth
def displaymeasurement(self, side):
print(self.side)
kitchen = room(10, 20, 15)
room.displaymeasurement("depth")
This is an abstraction of the code I'm using as that's too convoluted. I have striven to match it to the code in question, and it does produce the same error message.
Traceback (most recent call last):
File "/home/townsend/Documents/PycharmProjects/untitled2/Test/inplicitreference.py", line 13, in <module>
room.displaymeasurement("depth")
File "/home/townsend/Documents/PycharmProjects/untitled2/Test/inplicitreference.py", line 8, in displaymeasurement
print(self.side)
AttributeError: 'shape' object has no attribute 'side'
What syntax am I missing to communicate to the computer to replace side with the entered argument depth and process from there.
I have spent a couple of days searching but I can't seem to find an attempt at a similar construction. Perhaps it's because I'm using incorrect terminology. I am very new to this.
I don't expect this method to work but I thought it was the best way to illustrate. I have tried several different methods.
I am aware of a series of if checks as a solution but I'm convinced there's an simpler and more expandable solution.
def displaymeasurement(self, side):
if side == "length":
print(self.length)
if side == "bredth":
print(self.bredth)
if side == "depth":
print(self.depth)
You need to use the getattr builtin method. This allows you to search for an attribute of a class with a string.
class Room:
def __init__(self, length, bredth, depth):
self.length = length
self.bredth = bredth
self.depth = depth
def displaymeasurement(self, side):
print(getattr(self, side))
kitchen = Room(10, 20, 15)
kitchen.displaymeasurement("depth")
This is a fragile way to search for member's in an object's look up table. getattr() is intended for just this use case. Example below:
class MyClass(object):
def __init__(self):
self.x = 'foo'
self.y = 'bar'
myClass = MyClass()
try:
print(getattr(myClass, 'x'))
print(getattr(myClass, 'y'))
print(getattr(myClass, 'z'))
except AttributeError:
print 'Attribute not found.'
Sample Output:
foo
bar
Attribute not found.

How to call a stat from a class into a function - Python

I am struggling to create a health/anger (variables) drop when making the user fight a knight. I have defined a class called kingsmen, that is very simple and used for each knight, but I keep getting told that I am not calling the class properly. I'm not sure how to explain it. Below is the code for the class and for the knight, and the error message will be at the bottom. Some of the print spacing is weird (the ones with ''' ''') because the site is being difficult.
Thank you!
Class:
class kingsmen:
def __init__(self):
self.stats = {}
def attributes(self):
health=15
anger=7
self.stats["health"] = 15 #storing default health count
self.stats["anger"] = 7
return self.stats
def warning(self): #players will see this message when meeting a knight
print ('A kingsmen! Prepare for battle!')
def noise(self):
print ("H e y , i t ' s a v i l l a g e r !") #have these attributes later.
def death(self):
if healh == 0:
print ('''DEFEATED''')
Knight:
def rknightOne(kingsmen): #r stands for random, he will be one of 5 random villains you can face
rknightOne=kingsmen()
#while health in kingsmen.stats()!= 0 and anger != 0:
if action == 'attack':
for health in rknightOne.attributes:
health=health-1
print health
print_slowly ('I did not feel a thing. Ha ha ha!')
healthDrop(user)
elif action == 'mercy':
for anger in rknightOne.attributes:
anger=anger-1
print_slowly ('Huh. I feel something warm inside.')
elif action=='run':
print_slowly ('Not so fast!')
else:
print_slowly ("Jeez this guy is looney. I CAN'T UNDERSTAND YOU!")
Error:
Traceback (most recent call last):
File "C:/Python27/REDEMPTION/Redemption Game V1.py", line 678, in <module>
print randomKnight()
File "C:/Python27/REDEMPTION/Redemption Game V1.py", line 440, in randomKnight
print random.choice([rknightOne(kingsmen), rknightTwo(kingsmen), rknightThree(kingsmen), rknightFour(kingsmen), rknightFive(kingsmen)])
File "C:/Python27/REDEMPTION/Redemption Game V1.py", line 178, in rknightOne
for health in rknightOne.attributes:
TypeError: 'instancemethod' object is not iterable
The random function it's talking about is just cycling through 5 knights that could pop up. This is the code in case it's helpful:
def randomKnight():
print random.choice([rknightOne(kingsmen), rknightTwo(kingsmen), rknightThree(kingsmen), rknightFour(kingsmen), rknightFive(kingsmen)])
Change this
for health in kingsmen.stats():
with one of the following statements
for health in kingsmen.stats: # if you don't want to call the method
for health in kingsmen.stats(some_argument): # or if you want to call the method provide arguments
Reason you are getting this error is that you have defined both
self.stats = {}
and
def stats(self)
in kingsmen class, so it's confusing you.
With the latest revision of your code, it is clear what you are trying to do now. The error message you are seeing is telling you that you cannot iterate over an instance method. That is exactly what you are trying to do. You are trying to loop over kingsmen.attributes which is a method in your class. You cannot do that. Your method is actually returning a dictionary, and the result of executing that method is something you can iterate over. So you actually want to iterate over the result of calling attributes(). However, there is one more problem to clear up before that as I'll explain below.
In order to be able to properly call attributes, you have to instantiate your class (documentation on classes and objects in Python) first.
What you are doing is not executing the method, furthermore, not instantiating the class to be able to access and execute the method.
To resolve this, your line here:
for health in kingsmen.attributes:
You need to first instantiate your class, and then use the object from your class to call the attributes method. The return of that attributes method as you implemented will return the dictionary that you are trying to iterate over. So, your code should look like this:
my_kingsmen = kinsgmen()
for health in my_kinsgmen.attributes():

Python: None type object is not callable

I'm doing a game in pygame and what I'm trying to do, is to make an entity target another.
When I call the target function, I get "TypeError: NoneType object is not callable" What I understood after doing research on this error, is that it occurs, when you try to use the return value of a function that hasn't any.
But, my function isn't supposed to return something and I don't use a return value, so I'm a bit out of ideas.
I hope someone can help me, here is my code:
target function
def target(self,x,y):
target = self.world.getPointEntity(x,y)
if target != None and target.get_itarget():
self.set_target(target)
call to target function
self.player.target(x,y)
If you have any questions, feel free to ask.
EDIT: Code of getPointEntity function:
def getPointEntity(self, x, y, searchRange=24):
for entity in self.entities.itervalues():
if entity != None:
distance = entity.get_distance(x, y)
if distance < searchRange:
return entity
return None
As for the get_itarget function, it just returns True or False depending on the respective entity being a legal target or not.
The traceback points to line with self.player.target()
Full traceback:
__Main2.py", line 971, in <module>
Game(1920,1080)
__Main2.py", line 795, in __init__
self.run()
__Main2.py", line 910, in run
self.player.target(x,y)
TypeError: 'NoneType' object is not callable
EDIT: the method target belongs to the super class of the player class.
class Player(LivingEntity):
def __init__(self, name, world, image, x, y, speedModifier, sizeradius, inv_image, filler, shadow, scx, scy, animseq, animn):
LivingEntity.__init__(self, name, world, image, x, y, speedModifier, sizeradius, animseq, animn)
self.inventory = None
self.scx = scx
self.scy = scy
self.addInventory(inv_image, filler, shadow)
class LivingEntity(GameEntity):
def __init__(self, name, world, images, x, y, speedModifier, sizeradius, animseq, animn, xshift=48, yshift=48):
GameEntity.__init__(self, name, world, images, x, y, speedModifier, sizeradius, animseq, animn, xshift, yshift)
self.target = None
def set_target(self, target):
self.target = target
def target(self,x,y):
target = self.world.getPointEntity(x,y)
if target != None and target.get_itarget():
self.set_target(target)
I kind of solved the problem by putting the check for a target entity outside of the target function. I can't really see the differnce but it seems to work.
Inside the LivingEntity class you have a method called target, and the syntax used by code within the LivingEntity class to refer to that LivingEntity.target method is self.target. But inside the LivingEntity.set_target method you overwrite self.target with the self.target = target assignment.
After that assignment, the next time you call the target method Python tries to make the call using whatever set_target has set self.target to, instead of calling the LivingEntity.target method that you expect it to use.
So you got that error message because you told set_target to set self.target to None.
As PM 2Ring pointed out, set_target overwrites the LivingEntity.target field with whatever it gets. But the problem starts even before that: the __init__ method destroys the target method before anyone gets a chance to call it.
Here's a stripped-down example of what's happening:
#!/usr/bin/env python3
class InitDestroysMethod(object):
def __init__(self):
self.target = None
return
def target(self):
return "This is the InitDestroysMethod.target method."
def main():
print("Class with __init__ and target method:")
print("InitDestroysMethod.target: ", end="")
print(InitDestroysMethod.target)
print("InitDestroysMethod.target(): ", end="")
print(InitDestroysMethod.target(None)) # Bogus "self" argument.
print()
print("Instance with __init__ and target method:")
print("InitDestroysMethod().target: ", end="")
print(InitDestroysMethod().target)
print("InitDestroysMethod().target(): ", end="")
print(InitDestroysMethod().target())
return
if "__main__" == __name__:
main()
Below is the output of this program:
Class with __init__ and target method:
InitDestroysMethod.target: <function target at 0x1266490>
InitDestroysMethod.target(): This is the InitDestroysMethod.target method.
Instance with __init__ and target method:
InitDestroysMethod().target: None
InitDestroysMethod().target(): Traceback (most recent call last):
File "./init_vs_method.py", line 30, in <module>
main()
File "./init_vs_method.py", line 25, in main
print(InitDestroysMethod().target())
TypeError: 'NoneType' object is not callable
As you can see, the uninstantiated class does have a target method (technically just a function --- when an object is instantiated, it will have a bound method with the self parameter bound to the object). It can be called like any other function, as long as you provide an argument for the self parameter. (That trick only works in this case because target doesn't actually use its self parameter, but it lets me prove that there's a callable function named target.)
But an instance of the class has already suffered the effects of __init__. In this case, __init__ sets the value of target in the instance dictionary to None. The old value of target was a bound method, but by the time you get a reference to the newly-created and initialized object, that old value has long since been discarded.
When you use a field like some_instance.target, the search for an entity named "target" starts in the instance dictionary. That dictionary does indeed have a key named "target". That the class has a function also named "target" makes no difference --- the name has already been found, and its value (None) gets used.
Then you try to call that None value as if it were a function or a method, and you get a TypeError.

Categories

Resources