How to get the number of input arguments of class(__init__)? - python

I want to make the class score in python that takes each subject's score and return its average and sum. I know if I receive 4 arguments than denominator of average should be 4, but how I can make it to fixed codes that changed by number of inputs?, not just count numbers and type 4. I tried Len(self) or using for loop to count but Len makes error and for loop isn't that easy.
class score:
def __init__(self, language, math, english, science):
self.language = language
self.math = math
self.english = english
self.science = science
...
def sum_scores(self):
result = self.language + self.math + self.english + self.science
return result
def average(self):
average = self.sum_scores()/4 # Here is the problem!
return average
This is my first question on stack. so sorry for my poor English and stupid questions.

Don't use 4 separate attributes in the first place. Use a dict to store the attributes; then you can query the size of the dict.
class score:
def __init__(self, language, math, english, science):
self.scores = {'language': language, 'math': math, 'english': english, 'science': science}
...
def sum_scores(self):
return sum(self.scores.values())
def average(self):
return self.sum_scores() / len(self.scores)
If you still want attributes for each individual score, use properties:
class score:
def __init__(self, language, math, english, science):
self.scores = {'language': language, 'math': math, 'english': english, 'science': science}
#property
def language(self):
return self.scores['language']
# etc.
def sum_scores(self):
return sum(self.scores.values())
def average(self):
return self.sum_scores() / len(self.scores)

Assuming that it is OK that you don't know the subjects for which the scores apply, you can just use unnamed positional arguments
class score:
def __init__(self, *args):
self.scores = args
...
def sum_scores(self):
return sum(self.scores)
def average(self):
return self.sum_scores() / len(self.scores)

For your case, you could just note that the quantity is 4
However, you may want to use **kwargs as an argument (you can use any name, this is just convention; ** assigns all the keyword args not specifically named to a dict) instead
SUBJECTS = ("math", "science" ... )
class MyClass():
def __init__(self, **kwargs): # also consider *args
self.subjects = {k: v for k, v in kwargs.items() if k in SUBJECTS}
def sum_scores(self):
return sum(self.subjects.values())
def average(self):
return self.sum_scores() / len(self.subjects)
>>> c = MyClass(math=10, science=8)
>>> c.sum_scores()
18
>>> c.average()
9.0
You may also want to consider reporting on arguments that are not used to help users find usage errors

You can use keyword arguments in your init function:
class Score:
def __init__(self, **scores):
self.classes = []
for _class, score in scores.items():
setattr(self, _class, score) # self.english, self.math, etc.
self.classes.append(_class) # ["math", "english"]
def sum_scores(self):
sum = 0
for i in self.classes:
sum += getattr(self, i)
return sum
def average(self):
return self.sum_scores() / len(self.classes)
By using **scores, you can dynamically iterate over all arguments passed into the function as a dictionary. Here, I use the setattr function to give the Score object a property of its class name, and its value is the corresponding value from the dictionary. That way, I can dynamically iterate over each class, whether 3 or 100 classes are provided as input.
score1 = Score(math=67, english=98, art=76)
print(score1.sum_scores())
print(score1.average())
>>> 241
>>> 80.3333333333

Related

I need to solve the problem, but I don't understand the problem myself, so I can't write the code

My code:
class Base:
def __init__(self, massa):
self.massa = massa
def get_area(self):
return [self.massa / 3, 'food']
class Predator(Base):
def __init__(self, massa):
super().__init__(massa)
def get_area(self):
list_inp = super().get_area()
list_inp[1] = 'meat'
return list_inp
class Omnivores(Base):
def __init__(self, massa):
super().__init__(massa)
def get_area(self):
list_inp = super().get_area()
list_inp[1] = 'feed'
return list_inp
class Herbivorous(Base):
def __init__(self, massa):
super().__init__(massa)
def get_area(self):
list_inp = super().get_area()
list_inp[1] = 'grass'
return list_inp
jaguar = Predator(70)
bear = Omnivores(120)
cow = Herbivorous(100)
animals = [jaguar, bear, cow]
Task:
Build three classes (basic and 3 descendants) describing some predatory animals (one of the descendants), omnivores (second descendant) and herbivores (third descendant). Describe in the basic class an abstract method for calculating the amount (in kg) and type of food needed to feed an animal in a zoo.
a) Order the entire sequence of animals in order of decreasing amount of food. If the values ​​match, sort the data alphabetically by name. Display the animal ID, name, type and amount of consumed food for all elements of the list.
b) Derive the first 5 animal names from the list obtained in point (a).
c) Remove the last 3 animal identifiers from the list obtained in point (a).
d) Organize writing and reading collections (dictionary) to/from the file.

Implementing rules in a class python

I am stuck on applying rules in a class like forcing some values to change if some rule is present and so on. However I am unable to pass rules to the class. Here is my code, and what i require:
class Item:
valid_item_dict = {"a":20, "b":30, "c":40, "d":50}
def __init__(self, item_id):
self.item_id = item_id
self.item_cost = Item.valid_item_dict.get(self.item_id)
class checks:
def __init__(self):
self.content = list()
def cheque(self, item):
self.content.append(item)
def totals(self):
self.total = sum([self.item_counter().get(itm)*Item.valid_item_dict.get(itm) for\
itm in list(self.item_counter().keys())])
return self.total
def item_counter(self):
self.item_count_list = [itms.item_id for itms in self.content]
self.item_count_dict = dict((item, self.item_count_list.count(item)) for item in
self.item_count_list)
return self.item_count_dict
# Adding items to the list
item1 = Item("a")
item2 = Item("a")
item3 = Item("a")
item4 = Item("b")
# instatiance of class
cx = checks()
cx.cheque(item1)
cx.cheque(item2)
cx.cheque(item3)
cx.cheque(item4)
cx.totals()
>>> 90 (20*3 (from a) + 1*30 (from b))
In normal cases this works fine but I have a ton of rules which I need to add and I was earlier thinking of adding if-else rules in totals method of "checks" class. But is their a more generalized way to add these rules. Rule is something like if we have 3 types of product a, then the value of 'a' reduces from 20 to 10.
I did go over this question and am trying to use this, but any help would be wonderful. (Python how to to make set of rules for each class in a game)
You may want to use a more direct loop to implement these rules and make your code clearer. I find it easier to maintain complex logic than trying to code golf a 1-line result:
from collections import Counter, namedtuple
Rule = namedtuple("Rule", ["threshold", "newvalue"])
"""rule: if count is greater than or equal to threshold, replace with newvalue"""
class Item:
rules = {'a': Rule(3, 10)}
...
class checks:
...
def totals(self):
counts = Counter(self.content)
self.total = 0
for count in counts:
value = Item.valid_item_dict[count]
rule = Item.rules.get(count, Rule(0, value))
if counts[count] >= rule.threshold:
value = rule.newvalue
self.total += value*counts[count]
return self.total
I'm assuming you want the result of your sample to be 60 and not 90.

If statement while using getters and setters?

I am trying to return the price of the computer based on "macType" which is the size of the computer. I cannot figure out where to integrate the if statement into my code, ahh!!!
class apple:
def __init__(self,pType,price):
self.__pType=pType
self.__price=price
def setpType(self,pType):
self.__pType=pType
def setprice(self,price):
self.__price=price
def getpType(self):
return self.__pType
def getprice(self):
return self.__price
class mac(apple):
def __init__(self,pType,price,macType):
apple.__init__(self,pType,price)
self.__price=price
self.__macType=macType
def setmacType(self,macType):
self.__macType=macType
def setmacPrice(self,price):
if(macType()=="11Inch"):
self.__price=float(price*.9)
elif(macType()=="13Inch"):
self.__price=price
elif(macType()=="15Inch"):
self.__price=float(price*1.2)
def getmacType(self):
return self.__macType
def getprice(self):
if (self.__macType == "11inch"):
return super(mac, self).getprice()*.9
elif (self.__macType == "13inch"):
return super(mac, self).getprice()
else:
return super(mac, self).getprice()*1.1
a1 = apple("computer",1000)
m1 = mac("computer",1000,"11Inch")
m2 = mac("computer",1000,"13Inch")
m3 = mac("computer",1000,"15Inch")
print("a1 is a ",a1.getpType(),"and it costs",a1.getprice())
print("m1 is a ",m1.getmacType(),"and it costs",m1.getprice())
print("m1 is a ",m2.getmacType(),"and it costs",m2.getprice())
print("m1 is a ",m3.getmacType(),"and it costs",m3.getprice())
Actual output should show that 11 inch is 900, 13 inch is 1000 and 15 inch is 1100.
Python string comparison is case sensitive. In your getprice method you user "11inch", but you give your construct "11Inch" notice the upper- and lowercase i? Does aren't going to compare equal. Just use the same everywhere, or even better, look into the enum module.

How to call objects from a class in a function of another class

I want to use an object of a class in a function of another class. I know it's a really easy thing to solve, but I still can't figure it out.
I have the following class that is an object of players
class Players():
def __init__(self, name_player, surname, age, height, wheight):
self.name_player= name_player
self.surname = surname
self.age= age
self.height= height
self.wheight= wheight
def __repr__(self):
return "{}, {}, {}, {}, {} //".format(self.name_player,self.surname,self.age,self.height,self.wheight)
Then I have this class of teams
class Teams():
def __init__(self, name, points, goals_in_favour, goals_against):
self.name= name
self.points= points
self.goals_in_favour= goals_in_favour
self.goals_against= goals_against
def __repr__(self):
return "{} : {} : {}: {}".format(self.name,self.points,self.goals_in_favour,self.goals_against)
Now in the function 'ages' I want it to return a list of the players with an age less or equal to the one on the file. If I write 'i.Players.age' it sends me an error, which is the right way to spell it?
def ages(lists_teams,age):
list_players =""
return [list_players + i for i in list_teams if (i.Players.age <= age)]
(I have to write it in a list comprehension way).
Thanks a lot in advance.
To help you understand.
1.If list_teams is already an list of objects...you cannot call i.Players, because i here is already an object.
2.list_players="" you should change it to []...."" is not a list, you cannot add object on to it.
3.Try not use i for object, it is normally used to indicate an index..
def ages(list_teams,age):
list_players =[]
return [list_players + [player] for player in list_teams if (player.age <= age)]

python unbound method again

This gets me into difficult time (sorry, i am still very new to python)
Thank you for any kind of help.
The error
print Student.MostFrequent() TypeError: unbound method
MostFrequent() must be called with
Student instance as first argument
(got nothing instead)
This Student.MostFrequent() is called all the way in the end (last line) and the def is last def in the class
EDITED - Naming convention
My long code
import csv
class Student:
sports = []
ftopics = []
stopics = []
choice_list = []
choice_dict = {}
def __init__(self, row):
self.lname, self.fname, self.ID, self.gender, self.sport, self.movie, self.movieyr, self.country, self.ftopic, self.stopic = row
self.sports.append(self.sport)
self.ftopics.append(self.ftopic)
self.stopics.append(self.stopic)
def print_information(self):
return (self.lname, self.fname, self.ID, self.gender)
def print_first(self):
return (self.lname, self.fname, self.sport)
def print_second(self):
return (self.lname, self.fname, self.movie, self.movieyr)
def print_third(self):
return (self.lname, self.fname, self.country)
def print_fourth(self):
return (self.lname, self.fname, self.ftopic, self.stopic)
def most_frequent(self):
for choice in self.choice_list:
self.choice_dict[choice] = self.choice_dict.get(choice, 0) + 1
self.mostFrequent = sorted([(v, k) for k, v in self.choice_dict.items()], reverse=True)
print self.mostFrequent
reader = csv.reader(open('new_mondy_csc_data_revise.csv'), delimiter=',', quotechar='"')
header = tuple(reader.next())
print "%-17s|%-10s|%-6s|%s" %header[:4]
print "-" * 45
students = list(map(Student, reader)) # read all remaining lines
for student in students:
print "%-17s|%-10s|%-6s|%3s" % student.print_information()
print "%-17s|%-10s|%s" %(header[0],header[1],header[4])
print "-" * 45
for student in students:
print "%-17s|%-10s|%s" %student.print_first()
print "%-17s|%-10s|%-16s|%s" %(header[0],header[1],header[5],header[6])
print "-" * 45
for student in students:
print "%-17s|%-10s|%-16s|%s" % student.print_second()
print "%-17s|%-10s|%s" %(header[0],header[1],header[7])
print "-" * 45
for student in students:
print "%-17s|%-10s|%s" %student.print_third()
print "%-17s|%-10s|%-15s|%s" %(header[0],header[1],header[8],header[9])
print "-" * 45
for student in students:
print "%-17s|%-10s|%-16s|%s" % student.print_fourth()
k = len(students)
# Printing all sports that are specified by students
for s in set(Student.sports): # class attribute
print s, Student.sports.count(s), round(((float(Student.sports.count(s)) / k) *100),1)
# Printing sports that are not picked
allsports = ['Basketball','Football','Other','Baseball','Handball','Soccer','Volleyball','I do not like sport']
allsports.sort()
for s in set(allsports) - set(Student.sports):
print s, 0, '0%'
Student.choice_list = Student.sports
X = Student()
X.most_frequent()
#class Search(Student):
# def __init__(self):
# Student.__init__
first read PEP-8 on naming conventions:
Method Names and Instance Variables
Use the function naming rules: lowercase with words separated by
underscores as necessary to improve readability.
second you are calling mostFrequest on the class Student, not an instance of it. Use the method on an instance instead:
student = Student(row)
student.MostFrequent()
use Student().MostFrequent()
edit:
beware that you use class attributes and this is dangerous. here an example:
>>> class Person:
... name = None
... hobbies = []
... def __init__(self, name):
... self.name = name
...
>>> a = Person('marco')
>>> b = Person('francesco')
>>> a.hobbies.append('football')
>>> b.hobbies
['football']
>>> a.name
'marco'
>>> b.name
'francesco'
>>> a.name = 'mario'
>>> b.name
'francesco'
>>> a.name
'mario'
>>>
as you can see i modify marco's hobbies and francesco's hobbies are modified consequentially.
What you probably want is to define most_frequent as a classmethod:
#classmethod
def most_frequent(cls):
for choice in cls.choice_list:
cls.choice_dict[choice] = cls.choice_dict.get(choice, 0) + 1
cls.mostFrequent = sorted([(v, k) for k, v in cls.choice_dict.items()], reverse=True)
return cls.mostFrequent
First, I recommend making function names lower case only.
The error you get results from the usage of MostFrequent as a static method. For this to work, you need to explicitly pass an instance of Student as first argument.
If called directly on an instance of Student, the instance will implicitly be passed as first argument.
Consider using the staticmethod decorator for static usage of functions.
You only rarely call methods on a class definition (Student)
Almost always, you create an instance of the class
someStudent = Student(someRow)
Then you call the method on the instance ("object"), someStudent.
someStudent.MostFrequent()
Student.MostFrequent means You're trying to use static method, not instance method. So You must first create instance by calling Student() and then call MostFrequent() on it.
P.S.: If this is not part of some arcane project, I urge you to follow PEP 8 and use most_frequent as method name.
in your class def, the method definition
def MostFrequent(self,mostFrequent):
has the extra variable mostFrequent that you probably don't want there. Try changing to :
def MostFrequent(self):

Categories