Problem finding array entry based on object attribute - python

i have been having problems with a function useing an object as an input, but not knowing the position of the object, so i have made a stripped down version of the code to exemplyfi
sett = []
class Test:
def __init__(self, name, number):
self.name = name
self.num = num
#staticmethod
def howmany(who):
print(who.number)
sett.append(Test('dog', 2))
sett.append(Test('cat', 5))
sett.append(Test('fish', 7))
Test.howmany(sett.index(Test.name == 'dog'))
if it worked at intended this would output '2' as that is the number of the object with name 'dog'.
pleas help thanks

Your code has a mix up between num and number. Besides that necessary fix, the index method returns ... an index, not a member of sett. Moreover, Test.name is wrong: Test is your class object, not an instance. You could use the next function to get a matching item.
As a side note: you can just create the list of three items in one go. There is no reason to call append repeatedly:
class Test:
def __init__(self, name, number):
self.name = name
self.number = number # fix
#staticmethod
def howmany(who):
print(who.number)
sett = [Test('dog', 2), Test('cat', 5), Test('fish', 7)]
Test.howmany(next(test for test in sett if test.name == 'dog'))
Another note: it is not clear to me why you want to define howmany as a static method and not as an instance method, unless you would foresee that who could be None, but that logic is currently missing.

Related

How to create a list of instances of a given class

I'm facing problem with my code. In fact, I need to create a list of instances of my class( Patent). The name of the list is patent_ints. But when I'm trying to verify if any element in that list is a Patent one, I'm always getting a False response. And when iterating the first element is like "<__main__.Patent at 0x7f107820b710>".
Here is my code, I need help !
import json
import datetime
patent_data = json.loads(open('NASA_data.json', "r").read())
unique_center = []
for thing in patent_data["Patent_Information"]["Results"]:
for val in thing:
if(val == 'NASA Center'):
unique_center.append(thing[val])
total_num_centers = len(set(unique_center))
class Patent:
def __init__(self, abbreviated_organization_name, dict_data):
self.org_name = abbreviated_organization_name
self.title = dict_data["Title"]
# initialize instance variable called year. The value can be extracted from dict_data.
# This should be a four digit string.
self.year = str(datetime.datetime.strptime(dict_data['Date'], '%m/%d/%Y').year) #dict_data['Date'].split('/')[2]
# initialize an instance variable called month. The value can be extracted from dict_data.
# This should be a two digit string.
self.month = str(datetime.datetime.strptime(dict_data['Date'], '%m/%d/%Y').month) #dict_data['Date'].split('/')[0]
# initialize an instance variable called day. The value can be extracted from dict_data.
# This should be a two digit string.
self.day = str(datetime.datetime.strptime(dict_data['Date'], '%m/%d/%Y').day) #dict_data['Date'].split('/')[1]
self.id = dict_data['Case Number']
self.access_limit = dict_data['SRA Final']
patent_ints = [Patent(i, data) for i in unique_center for data in patent_data["Patent_Information"]["Results"]]
patent_ints[0]
Thank you in advance!
<__main__.Patent at 0x7f107820b710> is the default representation of the class when you try to print it. Add an __str__ or __repr__ method to the class and define some custom logic to return your desired details as a string:
class Patent:
def __init__(self, abbreviated_organization_name, dict_data):
...
def __repr__(self):
# return a dictionary of items in the class but you can return whatever you want
# you could do f'{self.title} {self.id} {self.year}-{self.month}-{self.day}' but str(self.__dict__) is quick to test
return str(self.__dict__)

Adding a new object to a class with user-input(input) in python

I am trying to add new objects to a class(emne) but the new instances of the class needs to be created using user input. So i need a way to be able to chose the name for the object and set some of the values of the objects with user input.
I have already tried to create a function that passes the value of the user input into a x = emner(x) to create it but it only returns:
AttributeError: 'str' object has no attribute 'fagKode'
so i think my issue is that the value of the input is created as a string so that it is not understood as a way to create the function
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne():
nyttEmne = input("test:")
nyttEmne=Emne(nyttEmne)
expected result is that the code creates a new instance of the class.
If by choosing a name you mean your fagKode attribute, what you need is:
fagKode = input('Enter code: ')
Emne(fagKode)
You're adding the instances of Enme to the list in the constructor, so you don't need to save them to a variable.
Alternatively, you can handle that in the function:
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
def leggTilEmne():
nyttEmne = input("test:")
enme.append(Emne(nyttEmne))
I'm not sure what exactly you are asking, since you haven't responded to the comments. So,
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne(self, value): # <--- is this what you want
self.nyttEmne= Emne(value)
This is an example of when to use a class method. __init__ should not be appending to a global variable, though. Either 1) have the class method append to a class attribute, or 2) have it return the object and let the caller maintain a global list.
emne = []
class Emne:
emne = []
def __init__(self, fag_kode):
self.fag_kode = fag_kode
self.karakter = ""
#classmethod
def legg_til_emne_1(cls):
nytt_emne = input("test:")
cls.emne.append(cls(nytt_emne))
#classmethod
def legg_til_emne_2(cls):
nyttEmne = input("test:")
return cls(nyttEmne)
Emne.legg_til_emne_1() # Add to Emne.emne
e = Emne.legg_til_emne_2()
emne.append(e)

Where did I mess up in this program for tracking faction alliances?

I have a program that models kingdoms and other groups (called 'factions' in my code).
class Faction:
def __init__(self, name, allies=[]):
self.name = name
self.allies = allies
def is_ally_of(self, other_faction):
if self in other_faction.allies:
return True
else:
return False
def become_ally(self, other_faction, both_ally=True):
""" If both_ally is false, this does *not* also
add self to other_faction's ally list """
if self.is_ally_of(other_faction):
print("They're already allies!")
else:
self.allies.append(other_faction)
if both_ally == True:
other_faction.become_ally(self, False)
RezlaGovt = Faction("Kingdom of Rezla")
AzosGovt = Faction("Azos Ascendancy")
I want to be able to call a factions become_ally() method to add factions to the ally lists, like this:
RezlaGovt.become_ally(AzosGovt) # Now AzosGovt should be in RezlaGovt.allies,
# and RezlaGovt in AzosGovt.allies
What actually happens is this:
RezlaGovt.become_ally(AzosGovt)
# prints "They're already allies!"
# now AzosGovt is in the allies list of both AzosGovt and RezlaGovt,
# but RezlaGovt isn't in any allies list at all.
Whenever I try to call become_ally(), the code should check to make sure they aren't already allies. This is the part that isn't working. Every time I call become_ally(), it prints "They're already allies!", regardless of if they actually are.
I also tried to use if self in other_faction.allies:, but that had the same problem.
I strongly suspect that the problem is with my use of self, but I don't know what terms to Google for more information.
You can't use mutable arguments as the default argument to a function.
def __init__(self, name, allies=[]):
When the default is used, it's the same list each time, so they have the same allies; mutating one changes the other because they're actually the same thing.
Change to:
def __init__(self, name, allies=None):
if allies is None:
allies = []
Alternatively, copy the allies argument unconditionally (so you're not worried about a reference to it surviving outside the class and getting mutated under the class):
def __init__(self, name, allies=[]):
self.allies = list(allies) # Which also guarantees a tuple argument becomes list
# and non-iterable args are rejected
Change this function.
def is_ally_of(self, other_faction):
if other_faction in self.allies:
return True
else:
return False
Check your own data not that of the passed in object.
Also
def __init__(self, name, allies=[]):
Is a bug waiting to happen. Your allies list will be a static list shared between all instances. Instead use
def __init__(self, name, allies=None):
self.name = name
self.allies = allies or []

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.

how to select an object from a list of objects by its attribute in python

Apologies if this question has already been asked but I do not think I know the correct terminology to search for an appropriate solution through google.
I would like to select an object from a list of objects by the value of it's attribute, for example:
class Example():
def __init__(self):
self.pList = []
def addPerson(self,name,number):
self.pList.append(Person(self,name,number))
class Person():
def __init__(self,name,number):
self.nom = name
self.num = number
a = Example()
a.addPerson('dave',123)
a.addPerson('mike',345)
a.pList #.... somehow select dave by giving the value 123
in my case the number will always be unique
Thanks for the help
One option is to use the next() built-in:
dave = next(person for person in a.pList if person.num == 123)
This will throw StopIteration if nothing is found. You can use the two-argument form of next() to provide a default value for that case:
dave = next(
(person for person in a.pList if person.num == 123),
None,
)
A slightly more verbose alternative is a for loop:
for person in a.pList:
if person.num == 123:
break
else:
print "Not found."
person = None
dave = person
If those nom's are unique keys, and all you are ever going to do is access your persons using this unique key you should indeed rather use a dictionary.
However if you want to add more attributes over time and if you like to be able to retrieve one or more person by any of those attributes, you might want to go with a more complex solution:
class Example():
def __init__(self):
self.__pList = []
def addPerson(self,name,number):
self.__pList.append(Person(name,number))
def findPerson(self, **kwargs):
return next(self.__iterPerson(**kwargs))
def allPersons(self, **kwargs):
return list(self.__iterPerson(**kwargs))
def __iterPerson(self, **kwargs):
return (person for person in self.__pList if person.match(**kwargs))
class Person():
def __init__(self,name,number):
self.nom = name
self.num = number
def __repr__(self):
return "Person('%s', %d)" % (self.nom, self.num)
def match(self, **kwargs):
return all(getattr(self, key) == val for (key, val) in kwargs.items())
So let's assume we got one Mike and two Dave's
a = Example()
a.addPerson('dave',123)
a.addPerson('mike',345)
a.addPerson('dave',678)
Now you can find persons by number:
>>> a.findPerson(num=345)
Person('mike', 345)
Or by name:
>>> a.allPersons(nom='dave')
[Person('dave', 123), Person('dave', 678)]
Or both:
>>> a.findPerson(nom='dave', num=123)
Person('dave', 123)
The terminology you need is 'map' or 'dictionnary' : this will lead you to the right page in the python doc.
Extremely basic example:
>>> a = {123:'dave', 345:'mike'}
>>> a[123]
'dave'
The missing underscore makes plist a public property. I don't think that's what you want, since it does not encapsulate the functionality and you could call a.plist.append instead of a.addPerson.
class Example():
...
def filter(self, criteria):
for p in self.plist:
if criteria(p):
yield p
def getByNum(self, num):
return self.filter(lambda p: p.num == num)
dave = next(a.getByNum(123))
If the numbers are unique, you may also consider using a dictionary that maps from number to name or person instead of a list. But that's up to your implementation.

Categories

Resources