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

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.

Related

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

I'm getting this error:
[...], line 28, in <module>
PlayerDamage = Dice * int(set_p_w.player_damage)
AttributeError: 'NoneType' object has no attribute 'player_damage'
When I run this code:
import player
Dice = random.randrange(1, 7)
set_p_w = player.set_player_weapon()
PlayerDamage = Dice * set_p_w.player_damage
This is how player.set_player_weapon() looks like:
def set_player_weapon():
import items
player_weapon = items.WBrokenSword
player_damage = player_weapon.damage
I searched everywhere and tried a bunch of different solutions, but nothing helped me. What is wrong with my code?
From the code you posted, player.set_player_weapon() doesn’t return anything. So set_p_w is nothing. You are interacting with set_p_w as if it is an object, but set_player_weapon() doesn’t create an object, it just sets two local variables (player_weapon and player_damage) and then discards them when the function ends.
The simplest way to get this to work is to have your player.set_player_weapon() method return a tuple with that information so it can be stored in the a variable outside the function: (player_weapon, player_damage).
Tuple Method
def set_player_weapon():
import items
player_weapon = items.WBrokenSword
player_damage = player_weapon.damage
return (player_weapon, player_damage)
player_weapon_damage = player.set_player_weapon()
PlayerDamage = Dice * player_weapon_damage[0]
A better way would be to make an class for Player which has the attributes player_weapon and player_damage as well as methods like def set_player_weapon() that set and change its attributes.

Python - object has no attribute Error

I re-wrote the entire class from scratch in a separate file and everything magically worked, conditionals and all. So, I simply imported that class and a couple functions from the new file into the master file. I still have no idea what went wrong the first time around.
Note the issues below were technically solved. You can see a typo towards the bottom of the code. That, however, uncovered an issue where all of my conditionals (if, try, etc.) stopped functioning, which is why I re-wrote the class in a separate module
I would delete this post since it got everyone nowhere, but that's not how things work on Stack Overflow, apparently.
Alright, I've been learning Python 3.4 and decided to do some homework on the side as practice. I started making a script that does a very basic simulation of 2 people fighting, and would expand upon it with any new stuff I learn (such as adding a GUI).
The script started out fine, but the more changes I made the more errors started showing up. Now it's to the point where I can't access any fields of the "fighter" class without it throwing errors such as:
'duelist' object has no attribute '_duelist__health'
Besides "'duelist' object has no attribute '_duelist__XXX'", I've had 0 other errors besides typos.
Google unfortunately couldn't help with this one, so that's why I'm making my first StackOverflow post.
Here's the class down to the first error-happy field, "health":
class duelist:
def __init__(self):
self.name = "Duelist" #must not be ""
self.health = 5 #must be >0
self.damage = [1, 3] #random attack range. Must be >=0 0 and the first must not be higher.
self.skill = 10 #% chance to pass a skill check. Representative of parrying/dodging. Must be >=0
self.shield = True #can block?
self.shieldE = 80 #max block %. Must be >0
self.agility = 0.5 #rate of attack in seconds. Must be >=0.05
self.precision = 10 #critical hit chance. Must be >=0
self.critical = 2.0 #critical multiplier. Must be >= 1.1
#name
#property
def name(self):
return self.__name
#name.setter
def name(self, value):
if value != "":
self.__name = value
else:
print("Invalid Name.\n")
#name
#health
#property
def health(self):
return self.__health
#health.setter
def health(self, value):
try:
value = value(int)
if value>=1:
self.__health = value
else:
print("Health must be above 0.\n")
except:
print("Invalid Health.\n")
#health
Also, for those suggesting to change the field names to not include an ' __ ' (or to include an ' __ ' everywhere), that causes an infinite loop.
Typing exactly this:
class duelist:
def __init__(self):
self.health = 5
#property
def health(self):
return self.__health
#health.setter
def health(self, value):
self.__health = value
D = duelist()
print(D.health)
D.health = 15
print(D.health)
Correctly returns
5
15
Your code does:
Set the value of .name = inside __init__()
That goes through the setter, and sets .__name =
When you read it by .name that reads through the getter, and reads .__name
And your description of the problem "I can't access any fields of the "fighter" class", I suspect is wrong, because accessing some of them work.
Health doesn't, though, and on line 45 you have this:
value = value(int)
instead of
value = int(value)
So that causes the getter to throw an exception and print("Invalid Health.\n") and __health is never set.
With self.shield = True, the setter is trying to do:
if value.lower() == 'y':
and you can't call lower() on a boolean, so it crashes out before it ever gets to try to type(value) == bool, and __shield is never set.
The exception can be caused if your class does not define an attribute __health in its __init__() method. Trying to read its value will trigger the problem. The attribute will be created by calling the setter method (indirectly through attribute assignment), and after that the attribute becomes available.
Here is a simplified version of your class:
class Duelist:
def __init__(self):
# self.health = 5
pass
#property
def health(self):
return self.__health
#health.setter
def health(self, value):
self.__health = value
>>> d = Duelist()
>>> d.health
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "p.py", line 9, in health
return self.__health
AttributeError: 'Duelist' object has no attribute '_Duelist__health'
>>> d.health = 123
>>> d.health
123
So one way to fix it is to initialise the attributes using the same name:
class Duelist:
def __init__(self):
# self.health = 5 # this will also work
self.__health = 5
>>> d.health
5
>>> d.health = 123
>>> d.health
123
So, given that the exception will be raised if you do not initialise the property (self.health) or the underlying attribute (self.__health), have you posted the actual code that causes the problem in your question?

Python: TypeError: __init__() takes exactly 2 arguments (1 given)

I know this question has been asked several times, but none have managed to provide me with a solution to my issue. I read these:
__init__() takes exactly 2 arguments (1 given)?
class __init__() takes exactly 2 arguments (1 given)
All I am trying to do is create two classes for a "survival game" much like a very crappy version of minecraft. Bellow is the full code for the two classes:
class Player:
'''
Actions directly relating to the player/character.
'''
def __init__(self, name):
self.name = name
self.health = 10
self.shelter = False
def eat(self, food):
self.food = Food
if (food == 'apple'):
Food().apple()
elif (food == 'pork'):
Food().pork()
elif (food == 'beef'):
Food().beef()
elif (food == 'stew'):
Food().stew()
class Food:
'''
Available foods and their properties.
'''
player = Player()
def __init__(self):
useless = 1
Amount.apple = 0
Amount.pork = 0
Amount.beef = 0
Amount.stew = 0
class Amount:
def apple(self):
player.health += 10
def pork(self):
player.health += 20
def beef(self):
player.health += 30
def stew(self):
player.health += 25
And now for the full error:
Traceback (most recent call last):
File "/home/promitheas/Desktop/programming/python/pygame/Survive/survive_classe s.py", line 26, in <module>
class Food:
File "/home/promitheas/Desktop/programming/python/pygame/Survive/survive_classe s.py", line 30, in Food
player = Player()
TypeError: __init__() takes exactly 2 arguments (1 given)
I just want to make the classes work.
The code you used is as follows:
player = Player()
This is an issue since the __init__ must be supplied by one parameter called name according to your code. Therefore, to solve your issue, just supply a name to the Player constructor and you are all set:
player = Player('sdfasf')
The problem is that the Class Player's __init__ function accepts a name argument while you are initializing the Class instance. The first argument, self is automatically handled when you create a class instance. So you have to change
player = Player()
to
player = Player('somename')
to get the program up and running.
__init__() is the function called when the class is instantiated. So, any arguments required by __init__ need to be passed when creating an instance. So, instead of
player = Player()
use
player = Player("George")
The first argument is the implicit self, which doesn't need to be included when instantiating. name, however, is required. You were getting the error because you weren't including it.
Your code know expects that you input something in __init__ which you don't.
I have made a simple example below that does give you an idea where the error __init__() takes exactly 2 arguments (1 given) is coming from.
What I did is I made a definition where I give input to useless.
And I am calling that definition from __init__.
Example code:
class HelloWorld():
def __init__(self):
self.useThis(1)
def useThis(self, useless):
self.useless = useless
print(useless)
# Run class
HelloWorld()
If you have a definition like def exampleOne(self) it doesn't expect any input. It just looks a t itself. But def exampleTwo(self, hello, world) expects two inputs.
So to call these two you need:
self.exampleOne()
self.exampleTwo('input1', 'input2')

AttributeError: 'list' object has no attribute 'assignmentScores'

I don't understand the meaning of this problem or how to fix it!
I keep getting the problem AttributeError: 'list' object has no attribute 'assignmentScores'
What does this mean? and how do I fix this issue?
My code is:
class Student:
studentName = ""
studentCourse = ""
averageMark = 0
grade = "none"
assignmentScores = [1, 2, 3, 4]
def __init__(self, n, c, a, g,m):
self.studentName = n
self.studentCourse = c
self.averageMark = a
self.grade = g
self.assignmentScores = m
def getName(self):
return self.studentName
def getCourse(self):
return self.studentCourse
def getAverage(self):
return self.averageMark
def getGrade(self):
return self.grade
def getMarks(self):
return self.assignmentScores
def setAverage(self):
mark = self.averageMark
return mark
def setGrade(self):
grade = self.grade
return grade
def setMarks(self):
marks = self.setMarks()
return marks
def addMark(self):
score = list.append(self, self.assignmentScores)
def calculateAverage(self):
if len(self.assignmentScores) > 0:
average = sum(self) / float(len(self.assignmentScores))
return average
else:
return 0
def determineGrade(self):
return 0
print(calculateAverage(assignmentScores))
First, please use 4 spaces for all indentation, it helps a lot. PEP 8 is your friend and will keep everyone friendly and helpful.
As for your problem, after running the code myself and looking at the traceback, it looks like you assigned the self.assignmentScores list to self itself, so when you type self.assignmentScores you are looking up an attribute of self, which is now a list instead of an instance of the class.
This mistake comes from the way you called the method:
calculateAverage(assignmentScores)
This method only requires one argument, which is supposed to be an instance of the class Student, but not only are you calling the method directly from the class instead of from an instance, you are using the assignmentScores list as an argument for the method. This makes it so that the method calculateAverage() replaces self with self.assignmentScores so when you try to check if the list is empty the code is reading it as self.assignmentScore.assignmentScore instead of the intended way.
The way you have the class defined at the moment strongly encourages you to call the method like this.
billy = Student("","",0,"none",[1,2,3,4])
print(billy.calculateAverage())
There is another error standing in your way after you solve this problem, but a good look at the traceback and a careful reading of the relevant code will lead you to the solution. Right now all you need is a better understanding of classes and calling methods work.

ERROR: unbound method "method name" must be called with "Class Name" instance as first argument (got classobj instance instead)

I hope you guys can help me out here.
I've been given this error from the following code:
Traceback (most recent call last):
File "C:\Python27\Lib\idlelib\Tarea5.py", line 60, in <module>
bg.addBandit(b)
TypeError: unbound method addBandit() must be called with BanditGroup instance as first argument (got classobj instance instead)
The code:
from numpy import *
from matplotlib import pyplot as p
class Bandit:
power = random.uniform(15,46)
life = random.uniform(40,81)
def __init__(self, power, life):
self.power = power
self.life = life
class BanditGroup:
def __init__(self,a):
self.group = [a] #Where 'a' is an object of the class Bandit
def addBandit(self,b):
self.group.append(b) #Where 'b' is an object of the class Bandit
return self.group
howmanygroups = random.randint(4,11)
i = 0
j = 0
while i <= howmanygroups:
bg = BanditGroup
howmanybandits = random.randint(1,11)
while j <= howmanybandits:
b = Bandit
bg.addBandit(b) #<-- line 60
j+=1
bgposx = random.uniform(0,50000)
bgposy = random.uniform(0,50000)
p.plot(bgposx,bgposy,'r^')
i+=1
I'd really appreciate if someone could tell me what's going on here. I started learning python 2.7 about 2 months ago.
Thanks!
Try changing your code to (notice the parenthesis around class instantiation):
while i <= howmanygroups:
bg = BanditGroup(a)
howmanybandits = random.randint(1,11)
while j <= howmanybandits:
b = Bandit(power, life)
bg.addBandit(b) #<-- line 60
The problem is that addBandit requires an instance of BanditGroup to be used. Adding (...) after the class name will create one:
bg = BanditGroup(...)
Right now, you have bg pointing to the class itself, not an instance of it.
The same thing needs to be done here with Bandit:
b = Bandit(...)
Note: ... means to pass in the appropriate arguments. You made BanditGroup.__init__ with a required a parameter and Bandit.__init__ with required power and life parameters. Since I don't know what you want these to be, I left them out.
Yes probably need parens when you create an instance of your Bandit and BanditGroup classes. Otherwise, you're assigning a class to your variables, not an instance of a class.
EG: bg = BanditGroup()

Categories

Resources