Which strategy follow to create class? - python

I am trying to learn how classes work. I would like to create different classes with some shared elements and others not, but as far as I know I can create it from three different ways:
Create a class with all the shared elements and then inherit this class and modify specific methods and attributes in the new class. Something like that:
class Enemy(object):
"""Enemy!"""
def __init__(self, damage=30, life=100, enemy="Hero"):
#And keep defining the class and its methods and attributes in common with all the enemys
class Troll(Enemy):
"""Troll!"""
def __init__ (self, defense=0):
#And define the specific attributes and methods for Trolls.
Create a class and ask for a type of class, and change the definition of the object from which input it got. Something like that:
class Enemy(object):
"""Enemy!"""
def __init__(self, damage=30, defense=0, life=100, type="Troll" enemy="Hero"):
if type=="Troll":
#Do that for type "Troll"
if type=="Goblin":
#Do that for type "Goblin"
#And keep defining the class and its methods and attributes for each accepted type
Create two different classes and then do multiple inheritance:
class Enemy(object):
"""Enemy!"""
def __init__(self, damage=30, life=100, enemy="Hero"):
#And keep defining the class and its methods and attributes in common with all the enemys
class Trolls(object):
"""Trolls!"""
def __init__ (self, defense=1, shield=20):
#And define the specific attributes and methods for Trolls.
class SuperTroll(Enemy, Trolls):
I see the first one is the easy one that let me be more flexible to create multiple classes with shared methods and attributes. But the second one seems to me more easy to use(or at least I like it), and I can get out of the if conditionals whatever I want. And the third one could be practical for mixing different classes without any shared method or attribute, and if they share it wouldn't mess it (or it would?).
Which one is better?
But about writing in one or the other way it seems it is just a matter of strategy about how do you want your code. Is this correct?

The second example is not a good idea; it will lead to a lot of duplicated code, and you have to edit your Enemy class every time you come up with a new type of enemy character.
Picking between the first and third is trickier, and will depend on what you want to achieve ("a matter of strategy", as you have it).
The first, single inheritance from Enemy for Troll and Goblin, is useful because it allows you to define all the code that all Enemy characters will have once, and only define the differences in the Troll and Goblin classes. You could extend this further, and have Enemy inherit from a superclass (or metaclass) Character, that provides the really basic stuff for both Enemy and Hero classes (e.g. name, health, ...).
class Enemy(Character)
class Troll(Enemy)
The third example may be useful if you want to separate characters and roles, e.g. you could have
class FriendlyTroll(Troll, Friend)
and
class UnfriendlyTroll(Troll, Enemy)
if those roles are going to mean different instance attributes (e.g. the Friend mix-in might introduce a share method). This allows for more complexity in your character definitions, but if you are not going to use the extra functionality it is a lot of complication to get your head around, and may lead to intractable multiple-inheritance problems.
TL;DR: Use the first one! If you decide later that you really need to separate out roles into mix-in classes, that isn't too complex a task.

First one:
Proper way to go...You are inheriting from what is collectively "ENEMY". Here you can have common things that "ENEMY" has under the class and have individual classes for all types of enemy and also you can well override some of the methods that makes some kind of "ENEMY" distinct.
Second one:
Not nice or properly object oriented because what if "trolls" have some property that is not shared by other "enemy". You might say that it can go under "if" statement you have but this makes the code very-less manageable which is why you use OOP ( to manage the code, it's not all but one of the reason).
Third one:
I strongly suggest not using multiple-inheritance as far as possible. Google diamond death problem and you will know why. One rule for multiple-inheritence--"If you think you need multiple inheritance, you are probably wrong. If you know you have to use multiple inheritance, you are probably right."

Well, classes are what essentially describes differences in behavior of the objects of those classes. That is you may choose either approach but only after you sit down and decide:
in your program what is the difference between a given troll and an enemy in general. If there's such a difference (i.e. there're situations when "trolls" behave somewhat different from enemies in general, or have their own methods (actions) etc) then you need to differentiate class Troll and class Enemy. If all they differ is their name, then you probably don't need a separate class...
You need multiple inheritance (the 3rd case) only if you need to mix-in behaviors of two unrelated classes. Generally it's a hard way to go, with certain traps and pitfalls. But if you're clever and accurate enough then you may succeed with it.

Related

I'm new and would like some help racking my brain around how to structure an OOP "template", I'll use an example --

Let's say I make a game, where the ocean is my environment. So:
class Ocean:
def __init__(self):
pass
Next, I'd create another class, (not a child class, as I learned from you guys earlier):
class Fish:
def __init__(self, pounds, length):
pass
But now, I'd like to make a subclass here:
class Trout(Fish):
def __init__(self, fave_bait, fave_geo_loc):
super().__init__(self, pounds, length)
self.fave_bait = []
self.fave_geo_loc = []
def swim():
pass
def attack():
pass
Alright, all this said, THIS is where I fall apart. I have no idea how to start implementing logic in this framework. I suppose maybe I'm supposed to do stuff like swim = False, and tie that to some if statement, and then something else. But I really have a hard time "seeing" and visualizing what I'm supposed to do while looking at this from a bird's eye view.
I believe I'm supposed to parse all of this into smaller chunks, maybe create a mind map, but I'm lost. I just need to know how you yourself personally think through the process of executing piece by piece all this code.
I feel like I know what everything is, but now I'm stuck on how to put everything together.
"I have no idea how to start implementing logic in this framework" -Logic goes into the class methods, and data into class members. The idea of the class is to combine data and related methods together, and hide unnecessary implementation details from the users. If you will have various types of fish in your game, it might make sense to implement them as classes and put the individual data of each fish type into its own class. But you still need to decide what you concretely want to accomplish. Abstract fish will not do anything. For example, if the fish need to appear on the screen, you need to give the Fish class a concrete render() method that will render it on screen.
Also, all of your code will not be in the class methods. You will also have code outside any class that will create and manipulate fish etc. Classes are just a tool to help to organize your code. Their use is not mandatory. In fact, using too many classes can be detrimental. Beginners tend to write dozens of thin classes for no reason, just making the code very difficult for everybody else to read.

What would be the pythonic way to implement a class that represents "a list with a title"?

I am trying to better understand composition vs inheritance in python so I have crafted a hopefully simple example.
Suppose I want to implement a class TitledList that is intended to behave just like a standard list, but with an additional attribute title intended to hold a string containing the name of the list. The __repr__ and __str__ methods would likely have to be reimplemented to incorporate the title, but otherwise I'd like to retain all the native functionality of list. Initializers would accept an optional keyword-only argument title.
I can see two approaches to creating this class. I could go the composition route, and define a class with two attributes, .contents (a regular list) and .title. That would presumably look something along the lines of
class TitledList:
def __init__(self, contents=[], *, title=None):
self.contents = list(contents)
self.title = title
But I'm not sure how I would go about cribbing all the methods of list so I don't have to constantly be referring to my_titled_list.contents all over the place or reimplement all the list methods I use.
The other alternative is to do the thing that everyone on the whole Internet says not to do, and inherit from the list class. I think in that case I would do the initializer like this?
class TitledList(list):
def __init__(self, iterable=[], *, title=None):
super().__init__(iterable)
self.title = title
This seems a lot more straightforward to me. But surely everyone on the whole Internet says not to extend list for a reason.
What are the pros and cons here? Is there a simple way to make the composition solution work the way I intuitively want? Are there lots of drawbacks to the inheritance solution that I don't understand? Is there some third option I should be considering (UserList?)
There are several ways to do it.
Subclass collections.UserList instead of list. This is basically a wrapper around list designed to be extensible.
Subclass collections.abc.MutableSequence and implement all of the required abstract methods. This might be useful if you want to define a totally new sequence-like class.
Subclass list. This might actually be fine in limited scenarios like your TitledList example, where you're just adding a new attribute. But if you want to ovverride list's existing methods then this may not be a good idea.
Create a new object with a list attribute. This is simple and easy to understand, but might be inconvenient. It all depends on your use case.
Reference: Trey Hunner: The problem with inheriting from dict and list in Python

How to avoid class inheritance [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I've recently been dealing a lot with class inheritance on a project I'm working on, and I've started to become disenchanted with it as a programming concept. I do understand its appeal: it provides a clean way to extend an existing base class with new methods, thereby avoiding having to rewrite the same code multiple times and adding a nice logical structure to how classes are related to one another.
However, now that I've been using it more extensively, its drawbacks have become much more apparent. Not only does it add a layer of opacity to where a method or attribute comes from, forcing me to go down a rabbit hole of inherited classes every time I want to figure out where a given method is being defined, but it also breaks encapsulation by allowing you to unwittingly redefine public and private functions and variables in an inherited class.
Here's a very simple example of how easy it is to break things with inheritance.
class Parent:
def __init__(self):
self._private_var = 10
def add_ten(self, n):
return n + self._private_var
class Child(Parent):
def __init__(self):
self._private_var = 100
def add_hundred(self, n):
return n + self._private_var
Now, let's say I want to use Child's inherited .add_ten method:
c = Child()
c.add_ten(4)
>> 104
Since I unknowingly redefined Parent's ._private_var, the .add_ten method now adds 100 instead of 10.
Granted, inheritance might be dealt with slightly differently in other languages (I know Python doesn't have any truly "private" methods or variables, so perhaps this is not as much of an issue in Java or C++). Still, the downsides of inheritance seem to me to outweigh its advantages and make we want to avoid using it altogether if I can.
The issue is that the alternative seems to add a lot of redundancy.
For example, I could have defined ChildTwo as:
class ChildTwo:
def __init__(self):
self._parent = Parent()
self._private_var = 100
def add_ten(self, n):
return self._parent.add_ten(n)
def add_hundred(self, n):
return n + self._private_var
This would allow both .add_ten and .add_hundred to behave as expected, but it would also require me to manually add every method I would like to inherit from the Parent class, which seems wasteful in terms of keeping my code lean. This is especially true when there are multiple methods I'd like to inherit from Parent.
I'm also not sure (?) if instantiating the Parent class for every ChildTwo class might have some impact on performance.
What's the best way to avoid using inheritance while still avoiding code repetition as much as possible and having a minimal impact on performance?
Edit: Someone pointed out that this is a bad example, since .add_ten should probably be defined as n + 10 instead of n + self._private_var. That's a fair point, but it requires that I know how Parent is implemented, which may not always be the case. If Parent is in some external module then there's nothing I can do about it. Furthermore, if its implementation of .add_ten changes in the future, it has an impact on the Child class as well.
There are obviously no hard rules on when and when not to use inheritance. However, there are a few key things I do to help avoid issues.
I treat child classes as just extensions of the parent's logic. I therefore try to avoid overwriting objects, instead only extending them.
For example, I commonly have a parent class which receives the configs for a project. Then, any child classes can use these configs and do whatever necessary logic with them. All the configs are the same, they're not being changed, so inheritance will not cause any issues.
class Parent:
def __init__(self, name, configs):
self.name = name
self.theory = configs['theory']
self.log_file = configs['log_file']
...
class Child(Parent):
def __init__(self, name, configs):
super().__init__(name, configs)
I would not however have a method in the parent class that performed some action with the configs and then alter that method in the child classes. Despite that being perfectly acceptable python code, I find it easy to make mistakes and it adds unnecessary complexity. Why bother writing a method if you're going to constantly override it?
With multiple inheritance, if it's not something you've encountered before, it can be surprisingly easy to run into issues with "Method Resolution Order". The Diamond of Death or whatever other dramatic names it has. This occurs when multiple inheritance leads to ambiguity in how a child class should inherit from above it in the inheritance tree. For this reason I completely avoid ever making classes "siblings".
Inheritance can often scale badly. By which I mean, adding lots of logic to a pre-existing inheritance structure can cause issues. Maybe your child classes all used the parent class method in the same way but now you've a new child class which is slightly different. Ok so you can overwrite that method. But what if you begin adding more and more child classes which also need to overwrite that method? Now it makes sense to rewrite the base class method which means you need to rewrite all of the overwritten methods.
Sometimes inheritance will be instrumental in reducing repetition, other times it will be a headache for maintenance, testing and extension. As always in programming, if you find yourself writing the same thing over and over, you're doing something wrong. Knowing exactly what a class structure will be used for in the future, for me has been the best way of making sure any inheritance won't cause issues.
I would just say that your example seems a bit of a straw-man. You set up a demonstrably bad structure then dismiss inheritance as the reason for failure. If you're going to add ten, add ten, don't add some changeable variable.
Finally, while I have banged on about personal preference, be aware in the working environment, people's preferences will be drastically different to yours. You should understand how to use, extend and debug all different class structures.

Bolting on abstract behavior dependent upon the same base?

I'm hoping someone may be able to help me out with a design issue I'm dealing with. It's specifically in the game development domain, but I think it's really a broader issue that has probably been solved in an accepted way. I'm working in Python.
I have a GameObject class that holds the position of the object (and other general state attributes) and a reference to my Engine object, which holds information about the game world at large. GameObjects can be a categorized further: they can be VisibleGameObjects, PhysicalGameObjects (collidable), or both, in concrete form. For example, I could have an invisible boundary, which is physical, but does not have a visible representation.
VisibleGameObjects implement a draw() method that handles drawing functionality, delegating this through its parent's Engine reference. PhysicalGameObjects have bounding boxes, and define logic to handle collisions, also requiring access to GameObject attributes (acceleration, velocity, etc.)
The problem is, what happens when I'd like to define a concrete object that needs to inherit the behavior of both a VisibleGameObject, and a PhysicalGameObject (which both share a parent GameObject)? It's my understanding that this type of circular inheritance is a big-bad idea.
How can I refactor this to essentially bolt on the specific behaviors to a concrete child class (drawable, collidable) that depend on the state of the parent abstract class?
EDIT: My one thought was to assign them to concrete instances of GameObjects as components, favoring a has-a relationship over an is-a relationship. Even that doesn't seem so clean however; trying to check to see if an object is collidable by searching a "components" list for a collidable component doesn't seem great either.
It seems like you're looking for a trait
Unfortunately, python doesn't support traits natively, although there are multiple modules that try to implement the model.
My suggestion (unless you want to depend on the mentioned modules) would be to write abstract classes to expose the behaviour you want, but that don't inherit the main class - leaving that to a third class, which inherits both the main, and the behaviour-class.
It's probably less confusing with an example:
create a Visible abstract class that does not inherit from GameObject, and exposes all the intended behaviour/functions (as if it inherited from GameObject). Then, have VisibleGameObject inherit from both GameObject and Visible.
Obviously, you can only manage to write Visible on a dynamic language like python - otherwise the compiler would complain that it couldn't access inexistent fields.

Is anyone using meta-meta-classes / meta-meta-meta-classes in Python/ other languages?

I recently discovered metaclasses in python.
Basically a metaclass in python is a class that creates a class. There are many useful reasons why you would want to do this - any kind of class initialisation for example. Registering classes on factories, complex validation of attributes, altering how inheritance works, etc. All of this becomes not only possible but simple.
But in python, metaclasses are also plain classes. So, I started wondering if the abstraction could usefully go higher, and it seems to me that it can and that:
a metaclass corresponds to or implements a role in a pattern (as in GOF pattern languages).
a meta-metaclass is the pattern itself (if we allow it to create tuples of classes representing abstract roles, rather than just a single class)
a meta-meta-metaclass is a pattern factory, which corresponds to the GOF pattern groupings, e.g. Creational, Structural, Behavioural. A factory where you could describe a case of a certain type of problem and it would give you a set of classes that solved it.
a meta-meta-meta-metaclass (as far as I could go), is a pattern factory factory, a factory to which you could perhaps describe the type of your problem and it would give you a pattern factory to ask.
I have found some stuff about this online, but mostly not very useful. One problem is that different languages define metaclasses slightly differently.
Has anyone else used metaclasses like this in python/elsewhere, or seen this used in the wild, or thought about it? What are the analogues in other languages? E.g. in C++ how deep can the template recursion go?
I'd very much like to research it further.
This reminds me of the eternal quest some people seem to be on to make a "generic implementation of a pattern." Like a factory that can create any object (including another factory), or a general-purpose dependency injection framework that is far more complex to manage than simply writing code that actually does something.
I had to deal with people intent on abstraction to the point of navel-gazing when I was managing the Zend Framework project. I turned down a bunch of proposals to create components that didn't do anything, they were just magical implementations of GoF patterns, as though the pattern were a goal in itself, instead of a means to a goal.
There's a point of diminishing returns for abstraction. Some abstraction is great, but eventually you need to write code that does something useful.
Otherwise it's just turtles all the way down.
To answer your question: no.
Feel free to research it further.
Note, however, that you've conflated design patterns (which are just ideas) with code (which is an implementation.)
Good code often reflects a number of interlocking design patterns. There's no easy way for formalize this. The best you can do is a nice picture, well-written docstrings, and method names that reflect the various design patterns.
Also note that a meta-class is a class. That's a loop. There's no higher level of abstractions. At that point, it's just intent. The idea of meta-meta-class doesn't mean much -- it's a meta-class for meta-classes, which is silly but technically possible. It's all just a class, however.
Edit
"Are classes that create metaclasses really so silly? How does their utility suddenly run out?"
A class that creates a class is fine. That's pretty much it. The fact that the target class is a meta class or an abstract superclass or a concrete class doesn't matter. Metaclasses make classes. They might make other metaclasses, which is weird, but they're still just metaclasses making classes.
The utility "suddenly" runs out because there's no actual thing you need (or can even write) in a metaclass that makes another metaclass. It isn't that it "suddenly" becomes silly. It's that there's nothing useful there.
As I seed, feel free to research it. For example, actually write a metaclass that builds another metaclass. Have fun. There might be something useful there.
The point of OO is to write class definitions that model real-world entities. As such, a metaclass is sometimes handy to define cross-cutting aspects of several related classes. (It's a way to do some Aspect-Oriented Programming.) That's all a metaclass can really do; it's a place to hold a few functions, like __new__(), that aren't proper parts of the class itself.
During the History of Programming Languages conference in 2007, Simon Peyton Jones commented that Haskell allows meta programming using Type Classes, but that its really turtles all the way down. You can meta-meta-meta-meta etc program in Haskell, but that he's never heard of anyone using more than 3 levels of indirection.
Guy Steele pointed out that its the same thing in Lisp and Scheme. You can do meta-programming using backticks and evals (you can think of a backtick as a Python lambda, kinda), but he's never seen more than 3 backticks used.
Presumably they have seen more code than you or I ever has, so its only a slight exaggeration to say that no-one has ever gone beyond 3 levels of meta.
If you think about it, most people don't ever use meta-programming, and two levels is pretty hard to wrap your head around. I would guess that three is nearly impossible, and the that last guy to try four ended up in an asylum.
Since when I first understood metaclasses in Python, I kept wondering "what could be done with a meta-meta class?". This is at least 10 years ago - and now, just a couple months ago, it became clear for me that there is one mechanism in Python class creation that actually involves a "meta-meta" class. And therefore, it is possible to try to imagine some use for that.
To recap object instantiation in Python: Whenever one instantiates an object in Python by "calling" its class with the same syntax used for calling an ordinary function, the class's __new__ and __init__. What "orchestrates" the calling of these methods on the class is exactly the class'metaclass' __call__ method. Usually when one writes a metaclass in Python, either the __new__ or __init__ method of the metaclass is customized.
So, it turns out that by writing a "meta-meta" class one can customize its __call__ method and thus control which parameters are passed and to the metaclass's __new__ and __init__ methods, and if some other code is to be called before of after those. What turns out in the end is that metcalsses themselves are usually hardcoded and one needs just a few, if any, even in very large projects. So any customization that might be done at the "meta meta" call is usually done directly on the metaclass itself.
And them, there are those other less frequent uses for Python metaclasses - one can customize an __add__ method in a metaclass so that the classes they define are "addable", and create a derived class having the two added classes as superclasses. That mechanism is perfectly valid with metaclasses as well - therefore, so just we "have some actual code", follows an example of "meta-meta" class that allows one to compose "metaclasses" for a class just by adding them on class declaration:
class MM(type):
def __add__(cls, other):
metacls = cls.__class__
return metacls(cls.__name__ + other.__name__, (cls, other), {})
class M1(type, metaclass=MM):
def __new__(metacls, name, bases, namespace):
namespace["M1"] = "here"
print("At M1 creation")
return super().__new__(metacls, name, bases, namespace)
class M2(type, metaclass=MM):
def __new__(metacls, name, bases, namespace):
namespace["M2"] = "there"
print("At M2 creation")
return super().__new__(metacls, name, bases, namespace)
And we can see that working on the interactive console:
In [22]: class Base(metaclass = M1 + M2):
...: pass
...:
At M1 creation
At M2 creation
Note that as different metaclasses in Python are usually difficult to combine, this can actually be useful by allowing a user-made metaclass to be combined with a library's or stdlib one, without this one having to be explicitly declared as parent of the former:
In [23]: import abc
In [24]: class Combined(metaclass=M1 + abc.ABCMeta):
...: pass
...:
At M1 creation
The class system in Smalltalk is an interesting one to study. In Smalltalk, everything is an object and every object has a class. This doesn't imply that the hierarchy goes to infinity. If I remember correctly, it goes something like:
5 -> Integer -> Integer class -> Metaclass -> Metaclass class -> Metaclass -> ... (it loops)
Where '->' denotes "is an instance of".

Categories

Resources