Suppose I have my models set up like this:
class B(Model):
...
def __str__(self):
return "B"
class C(B):
...
def __str__(self):
return "C"
class A(Model):
b = ForeignKey(B)
def __str__(self):
print "A: %s"%(self.b)
a = A(b=C(...))
a.save()
print str(a) # Prints "A: B"
Maybe I'm a bit confused how django inheritance works. My intention is to have the program print "A: C" at runtime (since A.b is an instance of model C)
I think I might be asking about multi-table inheritance. But that's only if you know what instance of a subclass you want.
As another example of how I'm confused, I'd like to borrow the example from the docs:
# Assume Restaurant, Park, and Museum inherit Place
bills = Restaurant.objects.create(name="Bill's Pub", burger="Bill's Burger")
city_prk = Park.objects.create(name='City Park', num_trails=5)
nose = Museum.objects.create(name='Nose Museum', est=1940)
places = Places.objects.all()
I'll definitely get a list of 3 objects (of type Place) but I have no way of differentiating the types of places. For example, if I want to print out the str value of each place...
for place in places:
print str(place)
...python will just execute Place.__str__() and not Restaurant.__str__() (for the restaurant) or Park.__str__() (for the park). This doesn't seem to happen with "normal" python. Python should normally automatically find the lowest-inherited class and execute the overridden function from that (if B overrides a method from A, B's method will be executed).
Are my assumptions correct? Sorry for the long question (and sorry if it's not clear). I'm not exactly sure how to ask what I'm wondering.
You are correct that most python objects work that way, but django models do not. You are doing a multi-table inheritance. Which will create a parent table - B, and a child table - C. C would have a primary key named b_ptr_id which is also a foreign key to B.id. Since A contains a foreign key to B, that is what you get. You can reference the child object like this:
b_object = B.objects.get(…)
c_object = b_object.c
But of course if multiple tables inherited from B, you would not no which child object to extract. This utility might help you: https://django-model-utils.readthedocs.org/en/latest/managers.html#inheritancemanager it will do just what you need. Calling .select_subclasses() on a query set will automatically "cast" each object to whatever child object it "really" is.
Actually, after doing more research, I've found what I was looking for was the "polymorphic" app, found here: https://github.com/bconstantin/django_polymorphic
Related
In this example, am I violating LSP? Since straight up replacing the last two lines with an instance of a subclass will give me an error(as wage isn't initialised)?
person_1 = Employee('Brad')
person_1.print_name()
#dataclass
class Person:
name: str
def print_name(self):
print(self.name)
#dataclass
class Employee(Person):
wage: int
person_1 = Person('Brad')
person_1.print_name()
If so, then how can there ever be a non-violation of LSP when extending the constructor of a class (aside from placing optional attributes thereafter)?.
LSP says, that if something is true for a Person object (e.g. it has a name, the name is a string, it can print its name), it must be also true for an Employee object. In other words, every Employee is also a Person.
It does not state that an Employee object must be created the same way as a Person object. Every Employee is not only a Person. It has not only the name, but also a wage.
The second question:
If the Employee.print_name() method were redefined not to print the name, but for instance to return it as a string, that would break the principle.
Note that breaking the LSP does not require a code change, for instance if the Person's name format were changed from e.g. "first_name last_name" to "last_name, first_name" in the Employee, and that would cause the program to give incorrect output.
I know it's been answered already but i wanted to emphasize:
We need to differentiate between 2 relationships. One is the relationship between instances of Person and instances of Employee. The second one is the relationship between the 2 instances of type (The Person class itself, and the Employee class itself.)
In your case, LSP deals only with the former (everything that we can do with Person instances, we need to be able to do in the exact same way with Employee instances). It says nothing about the classes themselves.
Now, since python is very dynamic you could technically argue "Hey just wait second! There is something I can do with one and not the other!". Take a look at the following example:
# Assume we have an instance of either Person or Employee here
instance = _
# The following will work with Person instances but will raise an exception for Employee instances
instance_copy = type(instance)(instance.name)
I would say that you shouldn't count this kind of stuff. Let's call it an "unreasonable expectation of usage" that shouldn't be accounted for when considering the validity of your code structure in the vast vast majority of use cases.
The most important thing to remember is this:
B inherits from A != A (the class object itself) can be substituted by B (the class itself)
It depends on what you mean by the LSP.
Does it mean the strict LSP, like in Barbara Liskov's original paper, where the behaviour of the program should be unchanged by type substitution? (and even then it's a desired property, not an absolute requirement)
Or does it mean following the Person interface, in which case it would not be a violation, since you can't remove functions for the Person class in the Employee class? (Well, you technically could, but it's not a good idea to do that).
What do we call the relationship of a class towards its associated metaclass?
I'd like to fill the blank in the following two lines:
Class A is the metaclass of class B.
Class B is the ________ of class A.
In the documentation of the class, I am documenting a metaclass I am currently writing. I find my self typing "the class associated to this metaclass" very often in the python docstrings. Is there a single word which I can use to denote this kind of relationship in a more concise manner?
Condensed example in which I'd like to use a more concise nomenclature:
def __init__(mcl, what, bases=None, dict=None):
"""
Raises an exception if >> the class associated to this metaclass <<
contains a valid set of configuration decorators.
...
"""
The term "metaclass" itself already captures much of the relationship you are looking. A metaclass isn't really a special thing; it's just another type. The "magic" is that instances of this type also happen to be types. (What is a type? It's just a class which provides methods for objects.)
If anything, classes are the special things. You could imagine that metametaclasses exist: types whose instances are metaclasses, whose instances are classes. You could build up an infinite hierarchy of such metameta...classes. (In practice, this doesn't exist in Python. The root metaclass type has itself as its own metaclass, not some other higher-order metametaclass.) A class, then, is unique as the only sort of type whose instances cannot also serve as types.
The relationship you are looking for is just "class B is an instance of (meta)class A".
(Nothing I say here should be taken as a contradiction of jsbueno's answer; I think it's just a different perspective.)
There is no official nomenclature for that. The only way to go is the full formal way: "the class B for which A is the metaclass" or equivalent.
Technically one could just say that "class B" is an "instance of "class A" - but no other context given it would be very hard for anyone to figure out you are talking about class-metaclass relationship.
For the specific case you mention, though, it would work, I think - you could replace ">> the class associated to this metaclass << " for ">> the class which is an instance of this metaclass << "
I have a model named Foo. I can create a new instance of this model, and save it to the database, even if I assign a field name that doesn't exist. For instance:
foobar = Foo.objects.create()
foobar.abcdefg = True # The field abcdefg does not exist!
foobar.full_clean()
foobar.save()
Why won't Django throw an exception when assigning to a field that doesn't exist? How can I make it throw an exception, at least during full_clean?
Python lets you store attributes of any name on virtually on any instance. It's possible to block this (either by writing the class in C).
The reason it works is that most instances store their attributes in a dictionary. The dictionary is stored in an instance attribute called __dict__. In fact, some people say "classes are just syntactic sugar for dictionaries." That is, you can do everything you can do with a class with a dictionary; classes just make it easier.
You're used to static languages where you must define all attributes at compile time. In Python, class definitions are executed, not compiled; classes are objects just like any other; and adding attributes is as easy as adding an item to a dictionary. This is by design.
Actually the mere fact is that there is no such thing as a declaration. That is, you never declare "this class has a method foo" or "instances of this class have an attribute bar", let alone making a statement about the types of objects to be stored there. You simply define a method, attribute, class, etc. and it's added.
foobar is just an instance of a class. As with any instance, you can add attributes whenever you want:
>>> class Test(object):
... myval = 7
...
>>> t = Test()
>>> t.myval
7
>>> t.otherval = 'another'
>>> t.otherval
'another'
(As noted by Flimm in a comment, you can prevent this by adding a __slots__ attribute to your class)
You could use self.__dict__ in the full_clean method to check for extraneous attributes, but you will need to be able to determine what attributes are supposed to be there. Note that model instances have a _state attribute that will need to be left alone.
You can get a list of the field names on your model using this list comprehension (From this answer):
[f.name for f in self._meta.get_fields()]
So, then just iterate over self.__dict__ and raise an exception if any keys are found that are not in that list of model fields and do not start with an underscore.
I'm still pretty new to Python, so bear with me. Here is my problem:
I have a base class, lets call it a sports game:
class Game:
def __init__(self):
self.home_team = None
self.away_team = None
and I have multiple derived classes for each sport, but lets use baseball as an example:
class BaseballGame(Game):
def __init__(self):
self.home_pitcher = None
self.away_pitcher = None
So far everything is good. However I have another utility function in a separate python module which will generate and populate a list of all the games being played on a given day for that sport.
def fetch_game_data:
games = []
games_found_online = code_that_fetches_online_games
for online_game in games_found_online:
new_game = Game()
new_game.home_team = ...
new_game.away_team = ...
games.append(new_game)
return games
Its obviously much more complicated than this with a lot of parsing using BeautifulSoup, but you get the point. My problem is that this function returns a list of the Base class, but I need a list of the Derived class. The derived classes will be the ones calling this function to populate a list and operate on it. The way I see it, I have two options:
I could implement a dreaded circular dependency and have the fetch_game_data function know about all of the derived classes and call the derived class constructors instead of the base class constructors. The derived classes already need to import the fetch_data module, but now the fetch_data module will have to import all of the derived classes to know about their constructors. And what makes it worse is that the fetch_data module won't have any need to touch any of the derived class fields - it only populates base class fields. The circular dependency is JUST so I can create the objects.
I could implement code that downcasts a Base class Game to a Derived class Game (like BaseballGame). Then, when the fetch_game_data function returns all of the games I can just convert them all to a Derived class object and continue on my way. Unfortunately I haven't seen much in the way of how to implement this. I tried just changing the class variable, but then the code complains because Derived class variables don't exist.
Another option I considered, but quickly fell apart, was to send an existing list of derived class objects into the fetch_game_data function, and instead of creating new Game objects it would just populate existing ones. The problem is that I won't know how many game objects I need. The fetch_game_data function determines how many games are needed by parsing the webpage. I suppose I could send in the max number of games but using number_of_teams/2, but what if there is a double-header in baseball? This quickly falls apart. I suppose I could write a function that will fetch the game data and just return the number of games for the day. Then I could populate a list of Derived games that size and send it in to be populated. But I would have to fetch all the webpage data AGAIN and parse it AGAIN to populate the list.
Nothing but bad options! I'm hoping there is a simple and elegant solution that has just eluded me thus far. I'm open to any suggestions, including a redesign if it makes sense.
Thanks!
I am porting existing code from c++ and I encountered a similar problem.
I have a generic class X and type specific classes e.g. XInt, XStr etc. There is more differences between these classes than just the type of the value. In c++ it was easy: I have virtual X::compare(X const& other).
It is overridden in XInt. Inside the overridden method I first handle cases where the 'other' is not XInt and then do static_cast<XInt const&>(other).
It is clearly impossible in python. So here is my solution. I added a non-virtual non-public function to do actual comparison to XInt and did not annotate the type of the parameter:
def _compare(self, other) -> int:
<do-actual-comparison>
def compare(self, other: X) -> int:
<handle cases where other is not XInt>
return self._compare_worker(other)
Did not test it yet but mypy does not complain and it seems that it will work due to duck typing in python. Maybe something similar will work for you.
You can convert a class of instance after it is initiated, see example below:
class A:
def __repr__(self):
return "class A"
def convert(self):
'convert A to B class'
self.__class__ = B
def hello(self):
print('hello from A')
class B(A):
""
def __repr__(self):
return "class B"
def hello(self):
print('hello from B')
a = A()
print(a)
a.hello()
a.convert()
print(a)
a.hello()
# output:
>>> "class A"
>>> "hello from A"
>>> "class B"
>>> "hello from B"
In your case, you can convert the class Game to whatever subclass you want after the instance is created.
Python cannot cast an object to another class (even subclass).
You must use concrete class when you create the game object. It can be done in a factory method (e.g. create_game), like this:
def create_game(online_game):
if online_game.type == 'baseball':
return BaseballGame()
else:
return Game()
def fetch_game_data:
games = []
games_found_online = code_that_fetches_online_games
for online_game in games_found_online:
new_game = create_game(online_game)
new_game.home_team = ...
new_game.away_team = ...
games.append(new_game)
return games
I have read several documentation already but the definition of "class" and "instance" didnt get really clear for me yet.
Looks like that "class" is like a combination of functions or methods that return some result is that correct? And how about the instance? I read that you work with the class you creat trough the instance but wouldnt be easier to just work direct with the class?
Sometimes geting the concepts of the language is harder than working with it.
Your question is really rather broad as classes and instances/objects are vital parts of object-oriented programming, so this is not really Python specific. I recommend you buy some books on this as, while initially basic, it can get pretty in-depth. In essense, however:
The most popular and developed model of OOP is a class-based model, as opposed to an object-based model. In this model, objects are entities that combine state (i.e., data), behavior (i.e., procedures, or methods) and identity (unique existence among all other objects). The structure and behavior of an object are defined by a class, which is a definition, or blueprint, of all objects of a specific type. An object must be explicitly created based on a class and an object thus created is considered to be an instance of that class. An object is similar to a structure, with the addition of method pointers, member access control, and an implicit data member which locates instances of the class (i.e. actual objects of that class) in the class hierarchy (essential for runtime inheritance features).
So you would, for example, define a Dog class, and create instances of particular dogs:
>>> class Dog():
... def __init__(self, name, breed):
... self.name = name
... self.breed = breed
... def talk(self):
... print "Hi, my name is " + self.name + ", I am a " + self.breed
...
>>> skip = Dog('Skip','Bulldog')
>>> spot = Dog('Spot','Dalmatian')
>>> spot.talk()
Hi, my name is Spot, I am a Dalmatian
>>> skip.talk()
Hi, my name is Skip, I am a Bulldog
While this example is silly, you can then start seeing how you might define a Client class that sets a blueprint for what a Client is, has methods to perform actions on a particular client, then manipulate a particular instance of a client by creating an object and calling these methods in that context.
Sometimes, however, you have methods of a class that don't really make sense being accessed through an instance of the class, but more from the class itself. These are known as static methods.
I am not sure of what level of knowledge you have, so I apologize if this answer is too simplified (then just ignore it).
A class is a template for an object. Like a blueprint for a car. The instance of a class is like an actual car. So you have one blueprint, but you can have several different instances of cars. The blueprint and the car are different things.
So you make a class that describes what an instance of that class can do and what properties it should have. Then you "build" the instance and get an object that you can work with.
It's fairly simple actually. You know how in python they say "everything is an object". Well in simplistic terms you can think of any object as being an 'instance' and the instructions to create an object as the class. Or in biological terms DNA is the class and you are an instance of DNA.
class HumanDNA(): # class
... class attributes ...
you = HumanDNA() # instance
See http://homepage.mac.com/s_lott/books/python/htmlchunks/ch21.html
Object-oriented programming permits us
to organize our programs around the
interactions of objects. A class
provides the definition of the
structure and behavior of the objects;
each object is an instance of a class.
Objects ("instances") are things which interact, do work, persist in the file system, etc.
Classes are the definitions for the object's behavior.
Also, a class creates new objects that are members of that class (share common structure and behavior)
In part it is confusing due to the dynamically typed nature of Python, which allows you to operate on a class and an instance in essentially the same way. In other languages, the difference is more concrete in that a class provides a template by which to create an object (instance) and cannot be as directly manipulated as in Python. The benefit of operating on the instance rather than the class is that the class can provide a prototype upon which instances are created.