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.
:)
Related
I am pretty new to Python, and I am trying to work out the relationships between classes and inheritage etc.
Let's say that I have a class Student:
class Student():
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
def set_name(self, name):
self.name = name
This student can attend multiple courses:
class Course():
def __init__(self, title):
self.title = title
def get_title(self):
return self.title
def set_title(self, title):
self.title = title
And for each course there can also be multiple students.
So it's a manyToMany relationship.
My first thought is to create a third class called StudentCourse:
class StudentCourse(Student, Course):
student_courses = {}
def __init__(self, student, course):
self.student = student
self.course = course
def add_student_to_course(self, student, course, results):
self.student_courses[student] = {
'course': course,
'results': results
}
def get_student_courses(self, student):
return self.student_courses.get(student)
Is this the correct structure?
If so, my question is: within the Student class, how do I access the student_courses dictionary containing the particular student's courses and results?
EDIT
I want to be able to see which students attend a specific course, as well as get the results for each individual student attending a course.
Looking forward to your responses.
Inheritance is almost certainly the wrong way to express the relationship between Students and Courses. Inheritance indicates an IS-A relationship. Neither your students are courses, nor are your courses students. So IS-A is wrong.
What you probably want is HAS-A. Each Student HAS-A number of Courses they're enrolled in. Similarly, each Course has several Students enrolled. In a database you'd create relationship object to handle the many-to-many relationship, but in Python code you can use data structures instead. A list is a natural pick. Here's a design that adds a list of courses to each student and a list of students to each course:
class Student:
def __init__(self, name):
self.name = name
self.courses = []
def enroll(self, course):
self.courses.append(course)
course.students.append(self)
class Course():
def __init__(self, title):
self.title = title
self.students = []
def enroll_student(self, student):
student.enroll(self)
A note about getters and setters (unrelated to your main question): You usually don't need to write methods like get_name and set_name in Python. Usually you should just use the attribute directly if those methods are not doing anything (like validating the input or translating the output in some way). In other languages it is often a best practice to always write and use such methods even if you don't need them yet, but in Python, if you later decide you do need to do some validation, you can change the implementation of the attribute lookup into a method call using a property.
This is more of an opinion-based question than something that you can get a clear answer to. That being said, given that both Student and Course are two very different entities, being connected only by ownership, there is no point in creating a muxed class out of the two.
Instead, I'd recommend having them both handle their part of the many-to-many relationship in a double-linked fashion, i.e. when you add a Student to a Course, you also inform the Student that they now are part of that course and vice versa. Something like:
class Student(object):
def __init__(self, name):
self.name = name
self.courses = {} # we'll use a dict so that our courses can be mapped to results
def add_course(self, course):
if course not in self.courses:
self.courses[course] = {} # initialize each course with an empty dict
# feel free to use any fields you like, like results etc.
course.add_student(self)
def del_course(self, course):
self.courses.pop(course, None)
course.del_student(self)
def __repr__(self): # just to ease our printouts
return self.name
And:
class Course(object):
def __init__(self, title):
self.title = title
self.students = set() # a set ought to be enough
def add_student(self, student):
self.students.add(student)
student.add_course(self)
def del_student(self, student):
self.students.discard(student)
student.del_course(self)
def __repr__(self): # just to ease our printouts
return self.title
And then you can use them in both directions to establish your many-to-many relationship, e.g.:
# Create some students and courses
john = Student("John Doe")
jane = Student("Jane Doe")
foo = Course("Foo Course")
bar = Course("Bar Course")
And then:
# initial state
print("John courses: {}".format(john.courses)) # John courses: {}
print("Jane courses: {}".format(jane.courses)) # Jane courses: {}
print("Foo students: {}".format(foo.students)) # Foo students: set([])
print("Bar students: {}".format(bar.students)) # Bar students: set([])
# lets add John to Foo:
john.add_course(foo)
print("John courses: {}".format(john.courses)) # John courses: {Foo Course: {}}
print("Foo students: {}".format(foo.students)) # Foo students: set([John Doe])
# lets add Jane to Bar, the other way around
bar.add_student(jane)
print("Jane courses: {}".format(jane.courses)) # Jane courses: {Bar Course: {}}
print("Bar students: {}".format(bar.students)) # Bar students: set([Jane Doe])
# lets add John to Bar as well
bar.add_student(john)
print("John courses: {}".format(john.courses))
# John courses: {Foo Course: {}, Bar Course: {}}
print("Bar students: {}".format(bar.students))
# Bar students: set([Jane Doe, John Doe])
# finally, lets add some info for the Foo course to John
john.courses[foo]["results"] = 94
print("John courses: {}".format(john.courses))
# John courses: {Foo Course: {'results': 94}, Bar Course: {}}
And given that we use native structures - sets and dictionaries - to hold our relationships not only that we automatically guard against duplicated entries, we can also easily (and very fast) check for relationships, too, e.g.:
print("John is in Bar: {}".format(john in bar.students)) # John is in Bar: True
# or:
print("Bar is in John's courses: {}".format(bar in john.courses))
# Bar is in John's courses: True
print("Jane is in Foo: {}".format(jane in foo.students)) # Jane is in Foo: False
Then you can expand on it, e.g. to formalize the results you're storing and similar structures - you can continue developing the API to suit your needs. Good luck!
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.
My title may seem vague, but I'm sorry to save I have no other idea on how to phrase this. Assuming my model structure looks like this:
class Restaurant(models.Model):
name = models.CharField(...necessary stuff...)
class Cuisine(models.Model):
name = models.CharField(...necessary stuff...)
# thai chinese indian etc.
class Food(models.Model):
restaurant = models.ForeignKey(Restaurant, related_name='restaurant')
cuisine = models.ForeignKey(Cuisine, related_name='cuisine')
name = models.CharField(...)
What I want is a list of objects of Food of a specific restaurant. But the Food objects need to be under their respective Cuisine, so that I can easily access the Food through the context. Is it possible to achieve this in any way?
My current query:
q = Cuisine.objects.prefetch_related('cuisine')
q = q.filter(cuisine__restaurant_id=restaurant.id) # say restaurant.id=1
# here restaurant is the object which I have retrieved
Well, what it does is it filters the cuisines available to the restaurant, but lists all food within those cuisine. I want only the food available in the restaurant. I think I am missing something in the way I built my models, but I'm not certain. It would be really helpful if someone could point me to the right direction. Thanks.
Food.objects.filter(restuarant_id=1, cuisine_id__in=selected_cuisine_ids)
Here, selected_cuisine_ids is the list of IDs of whichever cuisines needed
In my opinion, you should use ManyToManyField with through argument. So your models should be like:
class Restaurant(models.Model):
name = models.CharField(...necessary stuff...)
cuisines = models.ManyToManyField(Restaurant, through='Food', related_name='restaurants')
class Cuisine(models.Model):
name = models.CharField(...necessary stuff...)
# thai chinese indian etc.
class Food(models.Model):
restaurant = models.ForeignKey(Restaurant, related_name='restaurant')
cuisine = models.ForeignKey(Cuisine, related_name='cuisine')
name = models.CharField(...)
In this way, your query would be like this:
Cuisine.objects.filter(restaurants__id=1)
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 got this problem writing a little GUI lib that maps classes to simple table views. Every class member of a certain type = column, and order of columns is important. But...
class Person(object):
name = None
date_of_birth = None
nationality = None
gender = None
address = None
comment = None
for member in Person.__dict__.iteritems():
if not member[1]:
print member[0]
output:
comment
date_of_birth
name
address
gender
nationality
...
ugh, the oder got all mixed up...desired output:
name
date_of_birth
nationality
gender
address
comment
Is there a way to do it without maintaining additional OrderedDict() of columns?
It's possible in Python3, through the use of PEP3115 which allows you to override the dict type in the metaclass while the class is being constructed (eg. to use an OrderedDict which tracks the insertion order). Here's an implementation of this approach:
class OrderedMeta(type):
#classmethod
def __prepare__(metacls, name, bases):
return OrderedDict()
def __new__(cls, name, bases, clsdict):
c = type.__new__(cls, name, bases, clsdict)
c._orderedKeys = clsdict.keys()
return c
class Person(metaclass=OrderedMeta):
name = None
date_of_birth = None
nationality = None
gender = None
address = None
comment = None
for member in Person._orderedKeys:
if not getattr(Person, member):
print(member)
In Python2, it's a lot more tricky. It would be achievable with something fairly hacky like introspecting the source, and working out the definition order from the AST, but that's probably a lot more trouble than it's worth.
If all you need is an aggregate of variables, perhaps you should use a namedtuple instead. It also maintains the order of the fields (as it's a tuple).
from collections import namedtuple
Person = namedtuple('Person', ('name',
'data_of_birth',
'nationality',
'gender',
'address',
'comment'))
print Person._fields
Ok, it's not an answer per se but a workaround that only works in the context of original question ("Every class member [which is an instance] of a certain type = column, and order of columns is important"). The solution is to introduce a class variable _count into the CertainType class, and increment it at every instantiation. After that all class members of the CertainType are packed into a list which is sorted using key=attrgetter('_count')
P.S. Omitting that "which is an instance" part was a mistake on my part and it has limited range of solutions considerably. Sorry for that.