Most efficient way of adding objects together - python-3.x

I was wondering if there is a quick way of adding attributes in objects together. If I had a 'Person' class like this and I was trying to add the 'age' attribute together from multiple 'Person' objects, then I could override the add function:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __add__(self, other):
return self.age + other.age
This works well for two objects, but if I had a list of 'Person' objects and I was trying to sum all the age attributes using the reduce() fuction for example, then this approach wouldn't work (to my knowledge), as the overriden add method would be trying to sum different types together as we are returning a float from the add function, not a 'Person' object.
I could get the age attribute from each 'Person' object and add it together but I was wondering if there was a more efficient way of handling this.

It does not logically make sense to add two people when what you want to add is their ages. Your problem is because if p1 + p2 is a number, then (p1 + p2) + p3 is a number plus a person, and you only defined how to add a person to a person, not add a person to a number.
But the root cause is that this is not a sensible case for overloading __add__. That only makes sense when the result would be another instance of the same class, not a number. Instead, just get the ages and add those. Note that this is not less efficient than operator overloading; it doesn't involve any attribute lookups that wouldn't have to be done either way.
p1.age + p2.age
# or on a list:
sum(p.age for p in people)
"Explicit is better than implicit."

Related

Can anyone explain me about __init_ in Python?

List item
class Car:
def __init__(self, color, brand, number_of_seats):
self.color = color
self.brand = brand
self.number_of_seats = number_of_seats
self.number_of_wheels = 4
self.registration_number = GenerateRegistrationNumber()
Hi all,
1)Referring to the above example, could anyone tell me what is the difference between specific attributed and "the other" attributes? What will happen if registration_number is treated as a specific attribute?
2)
class MyInteger:
def __init__(self, newvalue):
# imagine self as an index card.
# under the heading of "value", we will write
# the contents of the variable newvalue.
self.value = newvalue
If we consider this example, shouldn't it be self.newvalue = newvalue?
I think I know what you're asking (let me know if I'm wrong), but I think you're asking what the difference is between the attributes that are assigned by the parameters of __init__ (Instance Attributes), ones that are assigned inside the __init__ method but not with parameters (also Instance Attributes), and ones that are not assigned in the initialiser at all (Class Attributes). The difference here is that all (well, pretty much all) cars have 4 wheels, and the number plate is generated, not supplied. You could also do this, for example:
class Car:
number_of_wheels = 4
def __init__(self, color, brand, number_of_seats):
self.color = color
self.brand = brand
self.number_of_seats = number_of_seats
self.registration_number = GenerateRegistrationNumber()
As the number of wheels here is always assigned to the same value, across all instances, it is said to be a "Class Attribute" in this case. All other attributes here are “Instance Attributes” as they are specifically assigned to each instance. For a slightly better explanation, I recommend reading this:
https://www.geeksforgeeks.org/class-instance-attributes-python/
It doesn't actually matter what the instance attribute (self.value here) is called, you could call it whatever you want and it'd still work, but in most cases, you would indeed want to name the attribute the same as the parameter.
init function also called as magic function is a constructor function for a class. if you remember in java whenever we make a class the constructor method should have the same name as the classname but this is not the scenario in python . In python we make use of the init method
the difference between the class attributes and instance attributes is that the class attributes are common to every object that is created but the instance attributes are only accessible by the object that is created.
consider a example where data of students in a class is stored. In such case the class division will be same for all the students of that particular class so it can be common but names of all students are different and also their marks and so on and hence they should be different for everyone
in previous scenario the class division can be class attribute and the data of student like name , marks has to be instance attributes
examples of class attribute is as shown
class A:
Division = 5A
here the division is a class attribute
class B:
def __init__(self,name,marks):
self.name = name
self.marks = marks
here the name and marks are instance variables
now here we can also write self.username = name because we are storing the value of name variable in self.username so you can write any name there is no constraint on that
Also whenever you write __ in front of method or variable it means that the attribute is private and accessible by only class.

Python: communication between classes and design patterns

I have 4 classes that handle logic for a large project. I have Product that clients buy and i have to bill them. Nevertheless the price of those products is varying greatly according to many variables. I have create a class PriceGenerator that handles the pricing of the products, an Inventory class that checks if the 'Product' is still available and a 'Cart' class that contains a list of 'Product' for a total bill if the client buys many 'Product'
Class PriceGenerator:
def get_price(*args)
Class Product:
def prod_bill()
Class Inventory:
def get_inventory(*args)
Class Cart:
self.list_product = [product1, product2, product3,...]
def cart_bill(*args)
my first option:
pg = PriceGenerator()
pd = Product()
inv = Inventory()
cart = Cart()
I could pass the PriceGenerator and Inventory as argument of Cart
def cart_bill(pg, inv, amount):
bill = 0
for prod in self.list_product:
px = prod.prod_bill(pg)
bill_p = px * min(amount, inv.get_inventory(product_args))
bill += bill_p
Obviously as the number of methods grows in Product, it becomes very complicated to keep track of all the arguments you have to pass. you pass PriceGenerator and Inventory to Cart that are then passed to the product prod.prod_bill(pg), all those nested dependencies are very cumbersome to pass through all the objects and it makes the code much more complicated.
I could call pg and inv without passing it as arguments for example in Product as a global variable
def produce_bill(self):
price = pg.get_price(product_args)
inventory = inv.get_inventory(product_args)
but i really don't like not knowing what are the class/arguments required, necessary for the method.
As the project grows, what design pattern would you suggest?
I would recommend implementing a context object containing anything that is relevant to your process. I am assuming this is about placing an e-commerce order in the following example:
class OrderContext:
price_calculator: PriceCalculator
inventory: Inventory
cart: Cart
Now you can pass this object around for all operations that are involved in your process:
cart.add_product(context, product, amount)
This allows you to add/remove further bits to the context without modifying the signature of all your functions. The drawback is that this has the potential to massively increase the number of dependencies within your application (depending on how disciplined the programmers in your team are).

python class; which method for calculating mean, adding a new instance, adding a list of instances

I have a Python class of grades:
class Grades:
def __init__(self, student, grade):
self.name = student
self.grade = grade
How do I create a method that can calculate the mean of all grades? Should it be a class/static/instance method?
Also what is the best way to write a method to add a list of instances?
Finally which method could be written to delete all existing data (all instances)?
Thank you!

Creating a list of Class objects from a file with no duplicates in attributes of the objects

I am currently taking some computer science courses in school and have come to a dead end and need a little help. Like the title says, I need of create a list of Class objects from a file with objects that have a duplicate not added to the list, I was able to successfully do this with a python set() but apparently that isn't allowed for this particular assignment, I have tried various other ways but can't seem to get it working without using a set. I believe the point of this assignment is comparing data structures in python and using the slowest method possible as it also has to be timed. my code using the set() will be provided.
import time
class Students:
def __init__(self, LName, FName, ssn, email, age):
self.LName = LName
self.FName = FName
self.ssn = ssn
self.email = email
self.age = age
def getssn(self):
return self.ssn
def main():
t1 = time.time()
f = open('InsertNames.txt', 'r')
studentlist = []
seen = set()
for line in f:
parsed = line.split(' ')
parsed = [i.strip() for i in parsed]
if parsed[2] not in seen:
studentlist.append(Students(parsed[0], parsed[1], parsed[2], parsed[3], parsed[4]))
seen.add(parsed[2])
else:
print(parsed[2], 'already in list, not added')
f.close()
print('final list length: ', len(studentlist))
t2 = time.time()
print('time = ', t2-t1)
main()
A note, that the only duplicates to be checked for are those of the .ssn attribute and the duplicate should not be added to the list. Is there a way to check what is already in the list by that specific attribute before adding it?
edit: Forgot to mention only 1 list allowed in memory.
You can write
if not any(s.ssn==parsed[2] for s in studentlist):
without committing to this comparison as the meaning of ==. At this level of work, you probably are expected to write out the loop and set a flag yourself rather than use a generator expression.
Since you already took the time to write a class representing a student and since ssn is a unique identifier for the instances, consider writing an __eq__ method for that class.
def __eq__(self, other):
return self.ssn == other.ssn
This will make your life easier when you want to compare two students, and in your case make a list (specifically not a set) of students.
Then your code would look something like:
with open('InsertNames.txt') as f:
for line in f:
student = Student(*line.strip().split())
if student not in student_list:
student_list.append(student)
Explanation
Opening a file with with statement makes your code more clean and
gives it the ability to handle errors and do cleanups correctly. And
since 'r' is a default for open it doesn't need to be there.
You should strip the line before splitting it just to handle some
edge cases but this is not obligatory.
split's default argument is ' ' so again it isn't necessary.
Just to clarify the meaning of this item is that the absence of a parameter make the split use whitespaces. It does not mean that a single space character is the default.
Creating the student before adding it to the list sounds like too
much overhead for this simple use but since there is only one
__init__ method called it is not that bad. The plus side of this
is that it makes the code more readable with the not in statement.
The in statement (and also not in of course) checks if the
object is in that list with the __eq__ method of that object.
Since you implemented that method it can check the in statement
for your Student class instances.
Only if the student doesn't exist in the list, it will be added.
One final thing, there is no creation of a list here other than the return value of split and the student_list you created.

How to change instance methods of a super class in subclasses?

While i was doing exercises on inheritance concept of OOP, a question appeared in my mind, the question is about the below exercise:
import random
import time
class Character():
Character_list = []
def __init__(self, name, life=100, power=100):
self.name = name
self.life = life
self.power = power
def print(self):
print("\n{}\n{} character details:".format("-" * 80, self.name))
print("Name: {}\nLife: {}\nPower: {}\n{}".format(self.name, self.life, self.power, "-" * 80))
def attack(self):
attack = random.randrange(self.power + 1)
if self.power <= 0:
print("{} can't attack because power is empty".format(self.name))
return False
else:
print("{} is attacking...".format(self.name))
for i in range(80):
time.sleep(0.05)
print("-", end="", flush=True)
self.power -= attack
print("\n- Spent power: {}".format(attack))
print("- Remaining power: {}\n".format(self.power))
if attack == 0:
print("{} missed.".format(self.name))
return attack
def attacked(self, attack):
if attack != 0:
print("{} injured.".format(self.name))
self.life -= attack
print("- Remaining life: {}".format(self.life))
if self.life <= 0:
print("{} died.".format(self.name))
self.Character_list.remove(self)
class Barbarian(Character):
Character_list = []
class Wizard(Character):
Character_list = []
The question i would like to ask about the above codes is: There’s a super class called Character. The later created Wizard and Barbarian subclasses inherit all the functions of the super class. Suppose to be that the name of the power instance attribute from the super class is different for each subclass. For example, for the Barbarian subclass, it is strength, and for the Wizard subclass it is magic instead of power.
Should instance methods of the super class be copied to the subclasses, in order that each subclass uses the instance attribute of its own class instead of the power name, the super class instance methods should be renamed in the subclasses with their names changed? Or, for the action I want to do, how would you suggest a method other than rewriting the super class instance methods to subclasses by changing the name of the power? Thank you.
Full disclosure - I'm a c# dev trying to answer a python question (so this answer may turn out to be unintentionally hilarious...)
The two easiest avenues I can think of:
A) Declare a variable in your base class and then change your constructor to require a 'PowerWord' be passed in (and then put its value into your variable.) Any time anything tries to declare a new instance of some sort of character, they need to pass in what the PowerWord for that character will be (though I'd imagine you'd just have the derived classes pass it in.)
B) Use an abstract property. This basically says, "Hey, if you want to write a class that derives from me, you'd better have a 'PowerWord' property." Then, this lets you use that PowerWord up in the base class, without having to specify exactly what the PowerWord is (because every derived class will have an answer to what it's supposed to be.)
... anyway, yeah - you had the right idea. You should definitely not copy/paste those functions into each derived class just to change 'power' to 'strength' or to 'magic'.

Resources