Getting an "unresolved reference" error - python-3.x

I keep getting an "unresolved reference" error even though I made a statement to it.
verb_dict = {"say": say, "examine": examine}
The error is after the examine:
def examine(noun):
if noun in GameObject.objects:
return GameObject.objects[noun].get_desc()
else:
return "There is no {}".format(noun)
Did I do something wrong when coding it?
I am also using pycharm community edition.

I can't replicate your problem in PyCharm 2016.14 I run the following code with no issue:
class GameObject:
class_name = ""
objects = {}
def __init__(self, name):
self.name = name
GameObject.objects[self.class_name] = self
def examine(noun):
if noun in GameObject.objects:
return GameObject.objects[noun].get_desc()
else:
return "There is no {}".format(noun)
print(examine('try'))
Output is
>>> There is no try

This is the GameObject class.
I don't see a problem in there.If you need more tell me.
class GameObject:
class_name = ""
desc = ""
objects = {}
def __init__(self, name):
self.name = name
GameObject.objects[self.class_name] = self

Related

Multiple inheritance, super() and their correct use with arguments in Python

I'm trying to understand multiple inheritance in python. I think that "kinda" got it, but I'm missing a few pieces. I know that if I have two clases I can do something like:
class A():
def __init__(self,name):
self.name = name
class B(A):
def __init__(self,name):
A.__init__(self,name)
self.mm = False
self.name = name
b = B("Peter")
My problem is when I have more classes and each class has their own init arguments. At first glance, it makes like no sense to have something like this:
class A():
def __init__(self,name,arg_a1,arg_a2):
self.name = name
class B(A):
def __init__(self,name,arg_b1,arg_b2,arg_a1,arg_a2...):
A.__init__(self,name,arg_a1,arg_a2...)
self.mm = False
self.name = name
class C(B):
def __init__(self,name,arg_c1,arg_c2,arg_b1,arg_b2,arg_a1,arg_a2.........):
B.__init__(self,name,arg_b1,arg_b2,arg_a1,arg_a2...)
self.name = name
So I started to look how to do it in an efficient way and not just hardcode it. Thats when I came across with multiple inheritance and thats when my doubts started to arraise.
If I have 3 classes:
class A():
def __init__(self,name):
self.name = name
class B(A):
def __init__(self,name,*args,**kwargs):
super().__init__(*args,**kwargs)
self.mm = False
self.name = name
class C(B):
def __init__(self,a,j,*args,**kwargs):
super().__init__(*args,**kwargs)
self.a = a
self.j = j
c = C("p",1,5,name="p")
Why this give an error but adding name as an init argument does not?
In this other example, if I add another argument to A init's function the I get TypeError: __init__() got multiple values for argument 'name'.
class A():
def __init__(self,name,lastname):
self.name = name
self.lastname = lastname
class B(A):
def __init__(self,name,*args,**kwargs):
super().__init__(name,*args,**kwargs)
self.mm = False
self.name = name
class C(B):
def __init__(self,a,j,*args,**kwargs):
super().__init__(*args,**kwargs)
self.a = a
self.j = j
c = C("p",1,5,name="p")
So, after all this, several questions comes to my mind.
Why this TypeError is generated?
How can I make inheritance "smart"?
Do I always need to use *args and **kwargs with multiple inheritance?
And all this gets me to the point to the libraries I use daily. Probably some of them use this concetps (I don't know, I'm assuming). What happes when the user puts a kwarg that is not present in any class? How do python "knows" that name goes in class A and not class B or viceversa?

Decorators unexpectedly change constructor behavior in Python

Below, I show a simplified example of a more complicated code, but nonetheless, it fully represents the issue that I have encountered.
Part 1: this works fine, no issues:
class Animal():
def __init__(self, animal_name = "no name given"):
self.set_name(animal_name)
def get_name(self):
return self._animal_name
def set_name(self, animal_name):
self._animal_name = animal_name
class Dog(Animal):
def __init__(self, dog_breed = "no breed", dog_name = "no name given"):
self._dog_breed = dog_breed
super().__init__(dog_name)
def get_breed(self):
print(self._dog_breed)
x = Dog('Greyhound', 'Rich')
Part 2: after introducing getter & setter decorators, the code stops working:
class Animal():
def __init__(self, animal_name = "no name given"):
#THE LINE BELOW SEEMS TO CAUSE AN ISSUE
self.name(animal_name)
#property
def name(self):
return self._animal_name
#name.setter
def name(self, animal_name):
self._animal_name = animal_name
class Dog(Animal):
def __init__(self, dog_breed = "no breed", dog_name = "no name given"):
self._dog_breed = dog_breed
super().__init__(dog_name)
def get_breed(self):
print(self._dog_breed)
x = Dog('Greyhound', 'Rich')
Output: AttributeError: 'Dog' object has no attribute '_animal_name'
When I keep the decorators in Part 2 but change the constructor in the Animal class to:
class Animal():
def __init__(self, animal_name = "no name given"):
self._animal_name=animal_name
It works.
I am just curious why it doesn't work in the example above in Part 2?
Short answer:
The line
self.name(animal_name)
can be split in two parts:
tmp = self.name
tmp(animal_name)
First, self.name calls the getter and the result is treated as a function. The getter uses return self._animal_name and since the setter has never been called, the respective error occurs.
Long answer:
Let's take the following class:
class Animal:
def __init__(self, animal_name):
self.name(animal_name)
#property
def name(self):
return self._animal_name
#name.setter
def name(self, animal_name):
self._animal_name = animal_name
To understand what the line
self.name(animal_name)
actually does, you first need to understand decorators.
The code
#dec
def func(a, b, ...):
[...]
is equivalent to
def func_impl(a, b, ...):
[...]
func = dec(func_impl)
(except that you can not call func_impl directly). See, for example, PEP 318 for more information.
This means that you can write the Animal class from above without using decorators:
class Animal:
def __init__(self, animal_name):
self.name(animal_name)
def get_name(self):
return self._animal_name
name = property(get_name)
def set_name(self, animal_name):
self._animal_name = animal_name
name = name.setter(set_name)
In order to understand this code, you need to understand the builtin property, which is a class. See the python docs for detailed information.
The line name = property(get_name) creates an object of type property. When retrieving the value of the property, get_name is called.
The line name = name.setter(set_name) first calls name.setter(set_name), which creates a copy of the property, and then overwrites name with this copy. When assigning a value to the copy, set_name is called.
All in all, name is an object of type property that uses get_name as getter and set_name as setter.
How does this help?
You need to understand this: name is not a function. It is a property. It is not callable.
The problematic line
self.name(animal_name)
is actually equivalent to
self.get_name()(animal_name)
which this explains the error message: The constructor calls the getter, which tries to use return self._animal_name. But since the setter has not been called, yet, self._animal_name has not been set.

how to access to data from a class which is stored in another class in python?

This is my code. I got a problem when i want to print the information inside the class 'pokemon'
class trainer(object):
def __init__(self, name, pokemons = [], money = 0):
self.name = name
self.pokemons = pokemons
self.money = money
this is my first class which has every pokemon per trainer
class pokemon(object):
def __init__(self, name, attribute, attacks = {}, health = '==========='):
self.name = name
self.attribute = attribute
self.health = health
self.attacks = attacks
The other class where I take the pokemon to import to the other class
class fight():
def __init__(self, fighter1, fighter2):
self.fighter1 = fighter1
self.fighter2 = fighter2
def fighting(self):
if len(Trainer1.pokemons) >= 1 and len(Trainer2.pokemons) >= 1:
print('{} wanna fight against {}'.format(Trainer1.name, Trainer2.name))
keepgoing = True
print('{} got this Pokemons: '.format(Trainer1.name))
i = 0
for i in Trainer1.pokemons:
print(i)
#while (keepgoing):
else:
print('You gotta have pokemons to fight')
return False
I thought that creating a class named fight for getting in battle would be the most wise idea but I'd like to know another method to do it
Pokemon1 = pokemon('Charizard', 'Fire', attacks={'1':'ball fire', '2':'cut', '3':'fire blast', '4':'mega kick'})
Pokemon2 = pokemon('Charmander', 'fire', attacks={'1':'blast', '2':'scratch', '3':'heat', '4':'tear'})
Trainer1 = trainer('Santiago', pokemons=[Pokemon1, Pokemon2])
Pokemon3 = pokemon('Charizard', 'Fire', attacks={'1':'ball fire', '2':'cut', '3':'fire blast', '4':'mega kick'})
Pokemon4 = pokemon('Charmander', 'fire', attacks={'1':'blast', '2':'scratch', '3':'heat', '4':'tear'})
Trainer2 = trainer('Alejandra', pokemons=[Pokemon3, Pokemon4])
Okay my problem is in the class fight. when i want to print the names of the pokemons i get the following message:
Santiago got this Pokemons:
<__main__.pokemon object at 0x000002AAD9B64D00>
<__main__.pokemon object at 0x000002AAD9B92DF0>
i know that the pokemon class has various instances, but how can i access to them?
To make your life easier, I recommend that you implement the __str__ dunder method on pokemon. This will resolve the issue that you are seeing right now, and make future prints of pokemon much easier.
That would look something like this:
class pokemon(object):
def __init__(self, name, attribute, attacks = {}, health = '==========='):
self.name = name
self.attribute = attribute
self.health = health
self.attacks = attacks
def __str__(self):
return "Pokemon: %s (Health: %11s)" % (self.name, self.health)
When you print the 'Charmander' pokemon, it'll look something like this:
Pokemon: Charmander (Health: ===========)
Of course, you can change the return of the __str__ to return whatever you want out of the pokemon.

Unit test initializes class without calling parameters, how do I get the parameters into the class?

So I'm working with Linked Lists in python, and the UnitTest our professor gave us calls C = Course(), but asserts the values after. This is what they use to grade, but I can't find a way to call the class then wait for the variables, and apply them to the class without parameters so it doesn't crash. Thoughts? Am I missing something obvious?
Tried to only include the relevant code. If people need full code for clarification or just for kicks/giggles let me know.
import courselist
import course
def load_data(data):
with open(data) as f:
for line in f:
dline = line.strip().split(",")
C = course.Course(dline[0],dline[1],dline[2],dline[3])
course_list = courselist.CourseList()
course_list.insert(C)
return course_list
def main():
data = "data.txt"
full_list = load_data(data)
print(full_list.__str__())
main()
class Course:
def __init__(self, c_num, c_name, c_hour, c_grade):
self.c_num = c_num
self.c_name = c_name
self.c_hour = c_hour
self.c_grade = c_grade
self.next = None
class TestEmptyCourse(unittest.TestCase):
def test_course_creation(self):
# make sure that an empty course is correct
c = Course()
self.assertEqual(c.name(), "")
self.assertEqual(c.number(), 0)
self.assertEqual(c.credit_hr(), 0.0)
self.assertEqual(c.grade(), 0.0)
self.assertEqual(c.next, None)
I was missing something obvious... Hangs head in shame For those interested here's how to fix it. It's always when you ask for help that you get it just in time to look like an idiot haha. Thanks to those to checked it out. If someone has an alternate solution I'll be sure to upvote you
class Course:
def __init__(self, num=0, cname="", c_hr=0.0, cgrade=0.0, next=None):
self.num = num
self.cname = cname
self.c_hr = c_hr
self.cgrade = cgrade
self.next = None
def number(self):
return int(self.num)
def name(self):
return str(self.cname)
def credit_hr(self):
return self.c_hr
def grade(self):
return self.cgrade
def __str__(self):
return f"cs{self.num} {self.cname} Grade:{self.cgrade} Credit Hours: {self.c_hr}"

Name Error python, a text adventure game

So i have a problem, that i don't quite understand why it's happening. I get a (Name Error global variable "value" is not defined) when it should be on my weapons class.
from items import *
class weapons(Item):
def __init__(self, name, attack_damage, lifesteal = 0):
super(weapons,self).__init__(name, value, quantity=1)
self.attack_damage = attack_damage
self.lifesteal = lifesteal
Here is the class that weapons is getting it from that already has value defined.
class Item(object):
def __init__(self, name, value, quantity=1):
self.name = name
self.raw = name.replace(" ","").lower()
self.quantity = quantity
self.value = value
self.netValue = quantity * value
def recalc(self):
self.netValue = self.quantity * self.value
I already have a piece of code similar to this that is working, but for some reason this value error is happening. I'm just going to include it.
from character import*
class player(character):
def __init__(self,name,hp,maxhp,attack_damage,ability_power):
super(player,self).__init__(name, hp, maxhp)
self.attack_damage = attack_damage
self.ability_power = ability_power
and the class that player is getting its stuff from
class character(object):
def __init__(self,name,hp,maxhp):
self.name = name
self.hp = hp
self.maxhp = maxhp
def attack(self,other):
pass
as you can see i did it here and this piece of code works when i call a player.
You need to add the value argument to the __init__ constructor of the weapons class.
super needs a parameter value but you did not pass it into the init

Resources