I'm trying to code a product inventory project. I stumbled across this problem and have been searching since a few days but couldn't find any way to do it. How can I create a class inherited from the base class with user input..
Here is the base class:
class Product:
def __init__(self, title, color, price):
self.title = title
self.color = color
self.price = price
what I'm trying to achive is that user will be able to add products himself by lets say pressing 2 will ask him to enter the product type (coat) and than the parameters specific to the product which will create a new class inherited from the base class. Like this:
class coats(Product):
def __init__(self, material, size):
self.material = material
self.size = size
I can create instances with user input but creating inherited classes I couldn't figure it out. I appreciate if you could help. Thanks.
While you can generate classes dynamically with the type() function, you really do not want to do this here. Code generation to model user-generated data only leads to very, very difficult to manage code that looks up attributes and variable names dynamically.
Use a datastructure in your existing class to store user-generated data. All you need is a dictionary:
class Product:
def __init__(self, type, price, properties):
self.type = type
self.price = price
self.properties = properties
then to create a coat product use:
products = {}
products['coat'] = Product('coat', 10.0, {'color': 'some color', 'material': 'some material', size: 12})
where the various values, and the key in products are not literals but variables with user input.
Classes model your application, and contain the data. Don't create separate models for the data.
Related
I want to make Books/Customer/Loan Classes and make all my function to be part of the class, but instead I only make it worse (I think lol).
I know that my code needs a lot of correction (Make the code more readable) but still maybe some Hero here could help and save my day (Make me learn something new along the way)
P.S: I'm learning how to make readable code so be gentle LOL.
Example of Customer Class of my code:
class Customer:
"""
A class that represents the Customer object
"""
def __init__(self, customer_id, customer_name, customer_city, customer_age):
"""
A function that contains all the relevant information of customers
:param customer_id: Customer's ID
:param customer_name: Customer's name
:param customer_city: Customer's city of living
:param customer_age: Customer's age'
"""
self.customer_id = customer_id
self.customer_name = customer_name
self.customer_city = customer_city
self.customer_age = customer_age
def __str__(self):
return f"{self.customer_id},{self.customer_name},{self.customer_city},{self.customer_age}"
Example of function that I want to make it part of the Customer Class instead of using it as a regular Function:
def add_new_customer(customer_id, customer_name, customer_city, customer_age):
"""
A function that add new customer to the Library
:param customer_id: Customer's ID'
:param customer_name: Customer's name'
:param customer_city: Customer's city'
:param customer_age: Customer's age'
"""
# todo: try different method that can return dict. return customers_library["Customers"].append({"Customer's ID":customer_id,"Customer's Name":customer_name,"Customer's City":customer_city,"Customer's age":customer_age})
new_customer = customers_library["Customers"].append(
{"Customer's ID": customer_id, "Customer's Name": customer_name, "Customer's City": customer_city,
"Customer's age": customer_age})
with open('customers_data.pkl', 'wb') as customer_save:
pickle.dump(customers_library, customer_save)
return new_customer
First of all, add_new_customer shouldn't be part of Customer class. I would rather see it as a method of Library which could contains collection of all customers. But to make it class method you just need to put it inside class, remember about identation and instance of the class (self) as first parameter.
Another hint and good practice is to not duplicate names - instead of customer.customer_name just write customer.name. In add_customer function you already now you adding customer, so it can take just name, city and age.
id is an exception as it would shadow builting id function and it's really common in database so in that one case it's good to have customer_id.
Another hint, you could remove a lot code with dataclasses
class Customer:
"""
A class that represents the Customer object
"""
from dataclasses import dataclass
#dataclass
class Customer
customer_id: int
name: str
city: str
age: str
And if we go further, there are possibility to put alias on field with dataclass-json or with pydantic, look:
from pydantic import BaseModel, Field
class Customer(BaseModel):
customer_id: int = Field(alias="Customer's ID")
class Config:
allow_population_by_field_name = True
c = Customer(customer_id=10)
print(c.dict(by_alias=True)) # prints {"Customer's ID": 10}
Which will simplify customer adding a lot (actually you can pickle pydantic model directly but it's one more way to go).
Say I have a base class called Publication:
class Publication():
def __init__(self, title='Default', price='Default')
self.title = title
self.price = price
def gettitle(self):
self.title = input("Please type in a title: ")
def getprice(self):
self.price = input("Please type in a price: ")
And a subclass called Book that inherits from Publication:
class Book(Publication):
def __init__(self, title, author, pages, current_page, price):
super().__init__(title, price)
self.author = author
self.pages = pages
self.current_page = current_page
def turnpage(self.current_page):
self.current_page += 1
Let's say early on in the course of my program, I create an object from the Publication class:
item = Publication()
But later on I have to assign my title and my price:
item.gettitle()
item.getprice()
I input "Lord of the Rings" and 10.99 respectively so now
item.title = "Lord of the Rings"
and
item.price = 10.99
Now, let's say I have some logic in my program that, depending on the price or if the title matches a string in a list, then we know specifically it is a book (as opposed to something like a magazine or a newspaper) so now I'd like it to be
item = Book()
When I originally created my object from the Publication class, I didn't know it was a Book. But now that I know, is there a way for me to keep the attributes/methods bound to the originally created object while "extending"/"inheriting" the object (not sure if those are the right words) with the newly available attributes from the Book class?
item = Book(title=item.gettitle(), price=item.getprice())
Or you can add a method in Publication that will give you the array which contains all characteristics of class, and in the __init__ function get all needed parameters by array. Another way is to pass item as an argument so __init__ will get all attributes from created object
Suppose I have two classes Employee and Student:
class Employee():
def __init__(self, id):
self.id = id # the employee id
...methods omitted...
class Student():
def __init__(self, id):
self.id = id # the student id, different from employee id
...methods omitted...
Now I'd like to create a third class StudentEmployee which simply merges Employee and Student.
However, the goal is that both id are still kept in each inherited class.
Some thing like this:
class StudentEmployee(Employee, Student):
def __init__(self, employee_id, student_id):
Employee.__init__(self, employee_id)
Student.__init__(self, student_id) # overrides employee id
Note that both Student and Employee have the id attribute so in reality one will override the other.
The question:
How can I keep both id as they carry different meaning?
For example, is there some way to protect id from one class from being over-riden by another class.
approach 1
One natural way is to change the class definition to:
class Employee():
def __init__(self, id):
self.eid = id # now "id" changes to "eid"
...attributes names in methods updated as well
class Student():
def __init__(self, id):
self.sid = id # now "id" changes to "sid"
...attributes names in methods updated as well
However, I don't like this approach very much because eid is not as neat as sid.
Moreover, the above example might be too simplistic.
Let's imagine the two classes being "merged" have many shared attribute name, the code refactoring work won't be small.
Any other better ways?
I have a single collection that can represent multiple types of data:
class Taxes(db.Document):
meta = {'collection': 'taxes'}
type = db.StringField() # State, local, federal
owner = db.ReferenceField(User, unique=True)
name = db.StringField()
fiscal_year = db.IntField()
What I am wanting to do is have either a DynamicEmbeddedDocument or make this a DynamicDocument to hold different models.
For example:
class Taxes(db.Document):
...
# This is made up syntax
data = db.EmbeddedDocumentField(StateTaxes, LocalTaxes, FederalTaxes)
Or:
class Taxes(db.DynamicDocument):
...
class StateTaxes(Taxes):
state_name = db.StringField()
class LocalTaxes(Taxes):
locality_name = db.StringField()
The goal is to do this:
# Embedded Dynamic Document example
taxes = Taxes.objects(owner=current_user).all()
state_taxes = [tax.data for tax in taxes if tax.type == 'state']
state_names = [tax_data.state_name for tax_data in state_taxes]
# Dynamic Document example
taxes = Taxes.objects(owner=current_user).all()
state_taxes = [tax for tax in taxes if tax.type == 'state']
state_names = [tax.state_name for tax in state_taxes]
Notes:
I must be able to perform 1 query to get back all types**.
Models should be separate in order to allow for clean definitions.
This example is very small, there would be a growing number of Models with very different definitions**.
All Models will have 4 or 5 fields that are the same.
The dynamic data should be relatively easy to query.
**These are the main reasons I am not using separate collections
Is this possible?
You could make a base class that covers all the base attributes (fields) and methods that you need. For example:
class BaseTaxes(db.Document):
name = db.StringField()
value = db.IntegerField()
meta = {'allow_inheritance': True}
def apply_tax(self, value):
return value*(1+self.value)
With this base class you can then create different versions:
class StateTaxes(BaseTaxes):
state = db.StringField()
As such the StateTaxes class inherits both attributes of BaseTaxes and its methods (more details here). Because it inherits the BaseTaxes class, it will be saved in the same collection (BaseTaxes) and queries can reach all subclasses:
results = BaseTaxes.objects().all()
And then, to split results by subclass:
state_taxes = [item for item in results if isinstance(item,StateTaxes)]
I have the following nested dict:
world = {'europe' :
{'france' : ['paris', 'lion'],
'uk' : ['london', 'manchester']}},
{'asia' :
{'china' : ['beijing'],
{'japan' : ['tokyo']}}
I'm trying the following objects out of it:
class world:
continents = {} # dict of continents
class continent(world):
name = '' # name of the continent
countries = {} # dict of countries
class country(continent):
name = '' # name of the country
cities = [] # list of cities
class city(country):
name = '' # name of the city
The goal is to get all countries from the continent object and alternatively to get the country and the continent names from a city object.
What is the best way to do so in Python?
Inheriting from "higher" classes is incorrect here. If you inherit a class, that inheriting class is the parent class plus more. You're saying here that country is a continent and also is a world. That is clearly not true and unnecessary.
There is no necessary hierarchical relationship between those four classes. Worlds are worlds, continents are continents, countries are countries and cities are cities. It's enough for continents to contain a list of the countries they hold, or conversely for a country to hold a reference to the continent it's in. The classes themselves do not need a hierarchical relationship.
Consider also whether such a strict 1:1 relationship is useful. There are countries which exist on more than one continent, depending on how exactly you want to define these terms (colonies are fun). How to design this data structure really depends on the concrete goal you have for it.
Syntactically, the classes should be defined as
class World(object):
def __init__(self, continents):
self.continents = continents
class Continent(World):
def __init__(self, name):
self.name = '' # name of the continent
...
class Country(Continent):
def __init__(self, name):
self.name = '' # name of the country
...
class City(Country):
def __init__(self, name):
self.name = '' # name of the city
...
However, in this case it does not make any sense.
Subclassing means something else:
Class Animal(object):
pass
Class Dog(Animal):
pass
Class Snake(Animal):
pass
A dog is a specific type of animal. A dog is an animal. A snake is also an animal.
In your case, a Continent is not a type of World, a Country is not a type of Continent and so on.
Instead you want to relate those classes, which can live as separate classes or they can go one inside the other.
For example
class City(object):
def __init__(self, name):
self.name = '' # name of the city
class Country(object, cities):
def __init__(self, name, cities):
self.name = name # name of the country
self.cities = cities # it's a list of Cities instances
class Continent(object):
def __init__(self, name, countries):
self.name = name # name of the continent
self.countries = countries # it's a list of Countries instances
class World(object):
def __init__(self, continents):
self.continents = continents # it's a list of Continent instances
france = Country('France', [City('Paris'), City('Annecy'), City('St. Tropez')])
italy = Country('Italy', [City('Rome'), City('Milan')])
uk = Country('UK', [City('London'), City('Bath')])
europe = Continent('europe', [france, italy, uk])
...
Note: the above is just an example. It may not be the best way to do it in python for a number of reasons, depending on how you intend to manipulate the objects.
It's a wide and long subject.
I suggest to look online for a good tutorial about Object Orientation (also called OOP for Object Oriented Programming or OOD for Object Oriented Design).
Here is one tutorial, but there are thousands available online.
After that, you will be able to design the interfaces your objects should expose in order to offer a certain functionality at the local/application level.
Tip: using a RDBM (Relational Data Base Management System), would help you relating and managing the models. Learn about ERD's (Entity-Relationship Diagrams) to help you design your data model.
:)