AttributeError 'str' object has no attribute - python

I am new to python and I get stuck in this error. I want to print names and years of birth of animals in team in an order by the name. Now I am keeping getting printing years and names but without order. I wanted to use lambda but than error occures. Could you help me please?
class Animal:
def __init__(self, name):
self.name = name
class Team:
def __init__(self, name):
self.name = name
self.year_of_birth = year_of_birth
self.members = []
def add_member(self, member):
self.member = member
self.members.append(team.member)
def print_team(team):
list_members= []
for member in team.members:
list_members.append(member.name)
list_members.append(member.year_of_birth)
print('{} ({})'.format(member.name ,member.year_of_birth) )
print (list_members)
for memeber in list_members:
sorted(list_members, key = lambda member: member.name)
print (list_members)
team = Team('Wolves')
team.add_member(Animal('Josh', 2015))
team.add_member(Animal('Quinn', 2016))
team.add_member(Animal('Peter', 2010))
print_team(team)
line , in
sorted(memberlist, key = lambda member: member.name)
AttributeError: 'str' object has no attribute 'name'

Here is another possible solution:
In order to print an object of any class that you created, you must implement the __str__() method or the __repr__() method as an official string representation of your objects. So, here is the modified Animal class:
class Animal:
def __init__(self, name, year_of_birth):
self.name = name
self.year_of_birth = year_of_birth # Added this field because your created Animal objects had it in the example.
def __str__(self):
return self.name + " " + str(self.year_of_birth)
def __repr__(self):
return self.name + " " + str(self.year_of_birth)
Next thing, I simplified your add_member() method because there was no reason for self.member = member:
def add_member(self, member):
self.members.append(member)
Next, I modified your print_team() function like this:
def print_team(team):
list_members= []
for member in team.members:
list_members.append(member)
print("Unsorted: ")
print (list_members)
list_members.sort(key = lambda animal: animal.name)
print("Sorted by name: ")
print (list_members)
You can simply append any object of type Animal in the list_members list. After that, you can sort your list using sort() and then print it. The code below:
team = Team('Wolves',2015)
team.add_member(Animal('Josh',2015))
team.add_member(Animal('Quinn',2145))
team.add_member(Animal('Peter',3000))
print_team(team)
Produces the following result:
Unsorted:
[Josh 2015, Quinn 2145, Peter 3000]
Sorted by name:
[Josh 2015, Peter 3000, Quinn 2145]

Related

How to print one Attribute in a class in Python?

simply i have a class that has a method to print a specific attibute in a class example:
class Attr:
def __init__(self, name,
wattage):
self.name = name
self.wattage = wattage
def print_attr(self):
print("attribute in class is " + getattr(Attr, wattage)
the expected output is:
attribute name is wattage: test
You don't need a helper function for this, Python does not have restricted access. Simply access the attribute directly:
a = Attr("Name", 10)
print(a.wattage)
If you truly want to make a print method like this, there are two ways to do it:
class Attr:
def __init__(self, name, wattage):
self.name = name
self.wattage = wattage
def print_wattage(self):
print(f'Wattage in *instance* is {getattr(self, "wattage")}') # getattr gets by string name
def print_name(self):
print(f"Name in *instance* is {self.name}")

Trouble understanding classes in python

I am a beginner in python and I am having trouble understanding classes. I have a task that requires me to create a class that should return a students information e.g. name, id, age and marks. I have made a class but am having trouble with the output and keep on getting an attribute error:
print("Student: " + self.name + " ID: " + self.ID + " Age: " + self.age + " Mark: " + self.mark)
AttributeError: 'Student' object has no attribute 'age'
I was wondering if someone could explain what I am doing wrong here as I am quite lost.
Rest of the code:
import random
class Student:
def __init__(self, name, ID):
self.name = name
self.ID = ID
def setAge(self, age):
self.age = age
self.age = random.randint(0, 100)
def setMarks(self, marks):
self.marks = marks
self.marks = random.randint(0, 100)
def Display(self):
print("Student: " + self.name + " ID: " + self.ID + " Age: " + self.age + " Mark: " + self.mark)
student = Student("John", "ID123")
student.Display()
You didn't call student.setMarks() and student.setAge() , so marks and age attributes are not created in object yet.
The solution is to call these two methods before calling student.Display()
Python objects are a container that has attributes you can set. If you don't set an attribute but try to read it, you get an AttributeError, meaning that the attribute you are looking for does not exist.
Currently, student = Student(...) calls Student.__init__, which assigns the name and ID attribute of the object. You never call student.setAge or student.setMarks, so your object's age and marks attributes are never set and can not be accessed.
It is traditional to assign default values in the __init__ method if you want to generally avoid unexpected crashes like that.
Another thing is that rather having getter and setter methods, as Java would, for example, Python encourages the use of properties. Properties are objects in the class template that can be accessed like a normal attribute, but allow you to run arbitrary code in place of the access and assignment operators.
Putting all that together, you could write something like
class Student:
def __init__(self, name, ID, age=None, marks=None):
self.name = name
self.ID = ID
self.age = random.randint(0, 100) if age is None else age
self.marks = random.randint(0, 100) if marks is None else marks
#property
def marks(self):
return self._marks
#marks.setter
def marks(self, value):
# Example of a check you could do
if not isinstance(value, int):
raise TypeError('Marks must be an integer')
In your example, you try to access the variable, before the assignment. You would actually have to call student.setAge and student.setMarks with arguments.
On the other note, in your function setAge you instantly overwrite the value, so consider removing either first or second assignment:
def setAge(self, age):
self.age = age # first assignment
self.age = random.randint(0, 100) # second assignment
The age attribute is not set because it was never assigned:
student = Student("John", "ID123")
student.setAge(30) # John is 30 years old.
student.Display()
def __init__() works like a constructor. Try to include age attribute inside the __init__() function, call setAge() from __init__(), or setAge() explicitly before calling Display().
Good luck :)
A simpler version for your code:
import random
class Student:
def __init__(self, name, ID):
self.name = name
self.ID = ID
self.age = random.randint(0, 100)
self.marks = random.randint(0, 100)
def Display(self):
print("Student: " + str(self.name) + " ID: " + str(self.ID) + " Age: " + str(self.age) + " Mark: " + str(self.marks))
student = Student("John", "ID123")
student.Display()

How do i create a function that creates list and adds members to those list based on user input?

I've created a Class call groups- The user is suppose to give the "group" a name and add members to it as they see fit. Its a Class function that would create a list and add members to that list.
The code i currently have does produce an empty list.
I've tried using .append(), .join(), .insert()
class group:
def __init__(self, name, member):
self.name = name =[]
self.member = member.join(name)
test_one = group("church", "john")
print (test_one.name)
print(test_one.member)
I expected the output of
Church = ["john"]
You shouldn't be assigning a list to name, you should assign the list to self.member.
class group:
def __init__(self, name, member):
self.name = name
self.member = []
self.add_member(member)
def add_member(self, member):
self.member.append(member)
test_one = group("church", "john")
print (test_one.name)
print(test_one.member)
DEMO
You could also write self.member = [member] in __init__(), but this is more modular -- only one method needs to know how to add a member.

Dictionary keys not present though they are being added

This is my code :
class member:
def __init__(self, name):
self.name = name
def get_name(self, name):
self.name = name
def __str__(self):
return self.name
class create_graph:
def __init__(self):
self.some_dict = dict()
def add(self, name):
if name is None:
raise TypeError
print(name not in self.some_dict)
if name not in self.some_dict:
self.some_dict[name] = []
else:
print(str(name) + "is already present")
def link(self, p1, p2):
if p1 in self.some_dict:
self.some_dict[p1].append(p2)
else:
self.some_dict[p1] = [p2]
some_graph = create_graph()
list_person = ['abc', 'xyz', 'mno', 'pqr']
for person in list_person:
some_graph.add(member(person))
print(len(some_graph.some_dict))
for i in range(len(list_person)-1):
some_graph.link(i,i+1)
print(len(some_graph.some_dict))
I am not able to find the error in this code.
When the add function is called, I get the True message indicating it is added. The first print statement prints that the number of keys are 4 but after adding the links, it says the keys are 7.
I want to have just 4 even after adding the link.
Thanks for the help !
Print out the dictionary in question.
print(some_graph.some_dict)
produces
{<__main__.member object at 0x7fe8326abe80>: [], <__main__.member object at 0x7fe8326abeb8>: [], <__main__.member object at 0x7fe8326abe48>: [], <__main__.member object at 0x7fe8326abef0>: []}
The keys of this dictionary are instances of the class member, not the strings in the list list_person.
I you did:
persons_in_graph_dict = {k.name for k in some_graph.some_dict}
for person in list_person:
print(person)
print(person in persons_in_graph_dict)
print()
You would get:
abc
True
xyz
True
mno
True
pqr
True
You can fix the problem by adding a __contains__() method to your CreateGraph class that expects a string argument called name. How to do this and then use it shown in the code below.
Note: I have changed all your class names to the CapitalizedWords-style to conform to the PEP8 coding guidelines (in its Naming Conventions section).
class Member:
def __init__(self, name):
self.name = name
def get_name(self, name):
self.name = name
def __str__(self):
return self.name
class CreateGraph:
def __init__(self):
self.some_dict = dict()
def add(self, name):
if name is None:
raise TypeError
if name not in self.some_dict:
self.some_dict[name] = Member(name)
else:
print("{} is already present".format(name))
def __contains__(self, name): # <-- METHOD ADDED.
return name in self.some_dict
some_graph = CreateGraph()
list_person = ['abc', 'xyz', 'mno', 'pqr']
for person in list_person:
some_graph.add(person)
print("checking these names in list_person:", list_person)
for person in list_person:
if person in some_graph:
print("Present")
else:
print("Not present")
Here's the output:
checking these names in list_person: ['abc', 'xyz', 'mno', 'pqr']
Present
Present
Present
Present
You are storing instances as key. call name()to get the name
try testing like below
for i in some_graph.some_dict:
print ((i.name) in list_person)

create python factory method

I have the following simple example:
class CatZoo(object):
def __init__(self):
raise NotImplemented
#classmethod
def make_zoo_cat(cls, name, age, gender, location):
cls._names = name
cls._ages = age
cls._genders = gender
cls._location = location
return cls
#classmethod
def make_zoo_cats(cls, names, ages, genders, location):
cls._names = names
cls._ages = ages
cls._genders = genders
cls._location = location
return cls
#property
def location(self):
return self._location
#property
def names(self):
return self._names
def age(self, name):
if name in self._names:
return self._ages[self._names.index(name)]
else:
return None
def gender(self, name):
if name in self._names:
return self._genders[self._names.index(name)]
else:
return None
#property
def meow(self):
return "meow!"
And I am trying to create an object of this class by using the following:
cat_zoo = CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC')
print "The name is {}".format(cat_zoo.names)
This is just an example, I am just trying to make my factory methods work (make_zoo_cat, make_zoo_cats). The first will be passed one name, age, gender and location where the second would be passed a list of names, ages and genders and one location. If I run this code, I get the following output:
The name is <property object at 0x7fe313b02838>
Thanks,
Remove the NotImplemented initializer and actually create instances of your class, instead of mutating the class itself:
class CatZoo(object):
def __init__(self, name, age, gender, location):
self._names = name
self._ages = age
self._genders = gender
self._location = location
#classmethod
def make_zoo_cat(cls, name, ages, genders, location):
return cls.mak_zoo_cats([name], age, gender, location)
#classmethod
def make_zoo_cats(cls, names, ages, genders, location):
return CatZoo(names, age, gender, location)
#property
def location(self):
return self._location
#property
def names(self):
return self._names
def age(self, name):
if name in self._names:
return self._ages[self._names.index(name)]
else:
return None
def gender(self, name):
if name in self._names:
return self._genders[self._names.index(name)]
else:
return None
#property
def meow(self):
return "meow!"
Note that there was no real difference other than the method name between make_zoo_cat and make_zoo_cats, the difference in argument names doesn't change the functionality here.
Instead, I presumed that ._names should always be a list and that make_zoo_cat (singular) should create a CatZoo with one cat name in it.
Just remember that Python is not Java; you really don't need all those property objects, not where you could just access the attribute directly.
You didn't create any object in your code.
In your make_zoo_cats you return cls, so you still have a class not an instance of this class.
This code will print the yes
if CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC') == CatZoo:
print 'yes'
You agree than you can't do that, since name its a property it will only exist if you have an instance of that class.
CatZoo.names
to be able to use the property you need on instance of that class
something like that (this will raise in your code):
cat = CatZoo()
cat.names # I can do this now
An other point in your make_zoo_cat you create Class variables, those variables are accessible from the class (no need to have an instance on that class) but are "common" to all.
c1 = CatZoo.make_zoo_cat('squeakers', 12, 'M', 'KC')
print c1._names
print c1._ages
print c1._genders
print c1._location
print '*'*10
print CatZoo._names
print CatZoo._ages
print CatZoo._genders
print CatZoo._location
print '*'*10
c2 = CatZoo.make_zoo_cat('other', 42, 'F', 'FR')
print c2._names
print c2._ages
print c2._genders
print c2._location
print '*'*10
print CatZoo._names
print CatZoo._ages
print CatZoo._genders
print CatZoo._location
print '*'*10
print c1._names
print c1._ages
print c1._genders
print c1._location
the result will be someting like that:
squeakers
12
M
KC
**********
squeakers
12
M
KC
**********
other
42
F
FR
**********
other
42
F
FR
**********
other
42
F
FR
The first two give me the same result, and the last three as well, this is because they are class variables and you always have the same class so modifying one of those variable will affect the other

Categories

Resources