What is the reason to create components and delegate behavior through them when we can add dependency directly to the method? To me, the latter seem to keep the door open for a behavior to change for existing objects, thus create looser couplings?
Composition/delegation:
class Human:
def __init__(self, legs):
self._legs = legs
def run(self):
self._legs.run()
def walk(self):
self._legs.run()
Inject dependency straight to method:
class Human:
def run(self, legs):
legs.run()
def walk(self, legs):
legs.walk()
Tell me, why should I bother with composition at all?
You should only use composition if it serves a purpose. In your example it serves no purpose since you could just call the methods directly on legs and don't bother with Human at all.
Expanding on your example, composition would make sense if each Human instance had its own distinct legs instance. In that case you need to keep track of which legs belongs to which Human, and the first example solves that.
Related
suppose I have a class which has 10 methods,
(i write pass here, but assume they would have some implementation)
class KlassOne:
def method_one(self, x):
pass
def method_two(self, y, z):
pass
...
def method_five(self, a):
pass
...
def method_ten(self, b):
pass
and a second class which inherits from the first one.
class KlassTwo(KlassOne):
def method_eleven(self, w):
pass
but KlassTwo does not want all ten methods of KlassOne,
let us say KlassTwo wants to inherit only these four methods,
wanted_methods = [method_one, method_three, method_eight, method_nine]
and the rest are not applicable for KlassTwo
one example could be,
KlassOne is Person
and KlassTwo is Robot
and method_five is EatsFood
so, our Robot does not want to inherit EatsFood
whereas method_one is BodyWeight, and let us assume it makes sense for both Person and Robot, so Robot wants to inherit method_one.
but how could this partial inheritance be achieved???
one way to do this is by using NotImplemented, for example,
class KlassTwo(KlassOne):
def method_five(self, a):
raise NotImplemented
and do the same for each method that is not wanted.
or the other way could be to use Composition, like,
class KlassTwo:
def __init__(self, x):
self.t = KlassOne.method_one(self, x)
something like that, and only use the methods that are wanted.
but I would like to use inheritance, and completely disable the inheritance of some methods,
that is something like,
class KlassOne:
#not_inheritable
def method_five(self, a):
pass
so that no subclass would get method_five.
how do I achieve this?
or give a list in KlassTwo, again like,
wanted_methods = [method_one, method_three, method_eight, method_nine]
and ensure that only these get inherited.
This doesn't directly answer your question of "How to inherit partially", rather is suggesting alternative in case of we're facing a XYZ problem.
Considering your human and robot example, it seems like your base class is not quite a baseline class(or generic) for what you're trying to do.
It might be better to define base class as Union of subclasses you're going to have, and add other Might-need-might-not features like EatsFood in subclass, or as Mixin.
For example, let's say we want to have Human, Humanoids, Monkey and Marcus Wright.
What they have in common: They are human-like entities with human shape.
Let's define base class with what usual human-like entities could do.
from __future__ import annotations
class HumanLike:
"""
Base class for human-like entities
"""
def __init__(self):
# some required attributes or setups
pass
def left_punch(self, target: HumanLike):
"""punch target with left fist"""
def right_hook(self, target: HumanLike):
"""Give nice right hook to target"""
def walk(self, pos):
"""Walk towards pos"""
Now we want to make Human, Humanoids and monkey. Then we can find something common between Human and Monkey, make such as mixin.
class BiologicalMixin:
"""
Mixin class for biological entities with basic needs
"""
def eat(self, food):
"""Eats given food"""
def breath(self):
"""Give that lung a fresh 'n nice air"""
class RoboticMixin:
"""
Mixin for Non-Biological entities with robot needs
"""
def recharge(self):
"""recharge energy"""
def robot_dance(self):
"""Pull out some sick moves that weak creatures can't"""
And then all we have to do would be subclassing these to make various stuffs.
class Human(HumanLike, BiologicalMixin):
"""
An obviously human like being with biological needs
"""
class Humanoid(HumanLike, RoboticMixin):
"""
A Human shaped robot
"""
class Monkey(HumanLike, BiologicalMixin):
"""
They love bananas!
"""
class TerminatorHybrid(HumanLike, BiologicalMixin, RoboticMixin):
"""
Marcus Wright would be here
"""
This is more common way of inheritance - Inheriting optionally isn't an inheritance.
If you really need such, best bet I can think of is to use composition and map methods you want manually.
I am extremely new to object-oriented programming, and am trying to begin learning in python by making a simple card game (as seems to be traditional!). I have done the following example which works fine, and teaches me about making multiple instances of the PlayingCard() class to create an instance of the Deck() class:
class PlayingCard(object):
def __init__(self, suit, val):
self.suit = suit
self.value = val
def print_card(self):
print("{} of {}".format(self.value, self.suit))
class Deck(object):
def __init__(self):
self.playingcards = []
self.build()
def build(self):
for s in ["Spades", "Clubs", "Diamonds", "Hearts"]:
for v in range(1,14):
self.playingcards.append(PlayingCard(s,v))
deck = Deck()
I want to make something now with more complex cards, not just a standard 52 deck (which has nicely incrementing values). The deck I have in mind is the [Monopoly card game][1]:
There are 3 fundamental types of cards - ACTION cards, PROPERTY cards, and MONEY cards. The action cards perform different actions, the property cards belong to different colour sets, and the money cards can have different values. Additionally, the property cards can be "wildcards", and can be used as part of one of two sets. Finally, every card also has an equivalent money value (indicated in the top corner of each card). In the rent action cards, the card can only apply to the colour property indicated on the card.
My question is just generally how to handle a situation like this, and what would be a nice way to include these different cards in a class-based python program? Should I keep my single PlayingCard() class, and just have many inputs, such as PlayingCard(type="PROPERTY", value="3M"). Or would it be better to create seperate classes such as ActionPlayingCard(), PropertyPlayingCard(), etc ? Or is there a better way? As I say, I am at the beginning of my learning here, and how to organise these types of situations in terms of the higher level design.
Many thanks.
These are what we call "design decisions". Often the "correct" way is a matter of opinion. As a beginner, I think it would be instructive to try both implementations to see how they work. There will be trade offs no matter which one you pick. You have to decide which of those trade offs are most important. Making these kinds of decisions will be informed as you gain more experience.
When you are approaching a problem with OOP, you usually want to model behavior and properties in a reusable way, i.e., you should think of abstractions and organize your class hierarchy based on that.
I would write something like the following:
class Card:
def __init__(self, money_value=0):
self.money_value = money_value
class ActionCard(Card):
def __init__(self, action, money_value=0):
super().__init__(money_value=money_value)
self.action = action
class RentActionCard(ActionCard):
def __init__(self, action, color, money_value=0):
super().__init__(action, money_value=money_value)
self.color = color
def apply(self, property_card):
if property_card.color != self.color:
# Don't apply
# Apply
class PropertyCard(Card):
def __init__(self, color, money_value=0):
super().__init__(money_value=money_value)
self.color = color
class WildcardPropertyCard(PropertyCard):
def __init__(self, color, money_value=0):
super().__init__(color, money_value=money_value)
class MoneyCard(Card):
def __init__(self, money_value=0):
super().__init__(money_value=money_value)
Due to Python being a dynamically typed language, OOP is a little harder to justify in my opinion, since we can just rely on duck typing and dynamic binding,
the way you organize your hierarchy is less important.
If I were to model this problem in C# for example, I would without a doubt use the hierarchy showed above, because I could rely on polymorphism to represent different types and guide the flow of my logic based on what type of card is being analyzed.
A couple of final remarks:
Python has very powerful builtin types, but most of the time
using new custom types that build on them makes your life easier.
You don't have to inherit from object since types in Python 3 (which is
the only one maintained as of today) inherit from object by default.
But, at the end of the day, there isn't a perfect answer, the best way would be to try both of the approaches and see what you're more comfortable with.
You could use inheritance.
This is where you create a main class then have sub-classes which still contain functions and values from the mother class however can also have extra values and functions for that specific class.
class Apple:
def __init__(self, yearMade):
pass
def ring(self):
print('ring ring')
class iPhone(Apple):
def __init__(self, number)
number = number
def func():
pass
Now the iPhone class has the same functions as the Apple class and its own function.
If you wish to learn more about inheritance I recommend doing some research.
For monopoly, i would design the game landings point of view. Not cards. Cards simply represent the landings for real world.
I want to do something like the following (in Python 3.7):
class Animal:
def __init__(self, name, legs):
self.legs = legs
print(name)
#classmethod
def with_two_legs(cls, name):
# extremely long code to generate name_full from name
name_full = name
return cls(name_full, 2)
class Human(Animal):
def __init__(self):
super().with_two_legs('Human')
john = Human()
Basically, I want to override the __init__ method of a child class with a factory classmethod of the parent. The code as written, however, does not work, and raises:
TypeError: __init__() takes 1 positional argument but 3 were given
I think this means that super().with_two_legs('Human') passes Human as the cls variable.
1) Why doesn't this work as written? I assumed super() would return a proxy instance of the superclass, so cls would be Animal right?
2) Even if this was the case I don't think this code achieves what I want, since the classmethod returns an instance of Animal, but I just want to initialize Human in the same way classmethod does, is there any way to achieve the behaviour I want?
I hope this is not a very obvious question, I found the documentation on super() somewhat confusing.
super().with_two_legs('Human') does in fact call Animal's with_two_legs, but it passes Human as the cls, not Animal. super() makes the proxy object only to assist with method lookup, it doesn't change what gets passed (it's still the same self or cls it originated from). In this case, super() isn't even doing anything useful, because Human doesn't override with_two_legs, so:
super().with_two_legs('Human')
means "call with_two_legs from the first class above Human in the hierarchy which defines it", and:
cls.with_two_legs('Human')
means "call with_two_legs on the first class in the hierarchy starting with cls that defines it". As long as no class below Animal defines it, those do the same thing.
This means your code breaks at return cls(name_full, 2), because cls is still Human, and your Human.__init__ doesn't take any arguments beyond self. Even if you futzed around to make it work (e.g. by adding two optional arguments that you ignore), this would cause an infinite loop, as Human.__init__ called Animal.with_two_legs, which in turn tried to construct a Human, calling Human.__init__ again.
What you're trying to do is not a great idea; alternate constructors, by their nature, depend on the core constructor/initializer for the class. If you try to make a core constructor/initializer that relies on an alternate constructor, you've created a circular dependency.
In this particular case, I'd recommend avoiding the alternate constructor, in favor of either explicitly providing the legs count always, or using an intermediate TwoLeggedAnimal class that performs the task of your alternate constructor. If you want to reuse code, the second option just means your "extremely long code to generate name_full from name" can go in TwoLeggedAnimal's __init__; in the first option, you'd just write a staticmethod that factors out that code so it can be used by both with_two_legs and other constructors that need to use it.
The class hierarchy would look something like:
class Animal:
def __init__(self, name, legs):
self.legs = legs
print(name)
class TwoLeggedAnimal(Animal)
def __init__(self, name):
# extremely long code to generate name_full from name
name_full = name
super().__init__(name_full, 2)
class Human(TwoLeggedAnimal):
def __init__(self):
super().__init__('Human')
The common code approach would instead be something like:
class Animal:
def __init__(self, name, legs):
self.legs = legs
print(name)
#staticmethod
def _make_two_legged_name(basename):
# extremely long code to generate name_full from name
return name_full
#classmethod
def with_two_legs(cls, name):
return cls(cls._make_two_legged_name(name), 2)
class Human(Animal):
def __init__(self):
super().__init__(self._make_two_legged_name('Human'), 2)
Side-note: What you were trying to do wouldn't work even if you worked around the recursion, because __init__ doesn't make new instances, it initializes existing instances. So even if you call super().with_two_legs('Human') and it somehow works, it's making and returning a completely different instance, but not doing anything to the self received by __init__ which is what's actually being created. The best you'd have been able to do is something like:
def __init__(self):
self_template = super().with_two_legs('Human')
# Cheaty way to copy all attributes from self_template to self, assuming no use
# of __slots__
vars(self).update(vars(self_template))
There is no way to call an alternate constructor in __init__ and have it change self implicitly. About the only way I can think of to make this work in the way you intended without creating helper methods and preserving your alternate constructor would be to use __new__ instead of __init__ (so you can return an instance created by another constructor), and doing awful things with the alternate constructor to explicitly call the top class's __new__ to avoid circular calling dependencies:
class Animal:
def __new__(cls, name, legs): # Use __new__ instead of __init__
self = super().__new__(cls) # Constructs base object
self.legs = legs
print(name)
return self # Returns initialized object
#classmethod
def with_two_legs(cls, name):
# extremely long code to generate name_full from name
name_full = name
return Animal.__new__(cls, name_full, 2) # Explicitly call Animal's __new__ using correct subclass
class Human(Animal):
def __new__(cls):
return super().with_two_legs('Human') # Return result of alternate constructor
The proxy object you get from calling super was only used to locate the with_two_legs method to be called (and since you didn't override it in Human, you could have used self.with_two_legs for the same result).
As wim commented, your alternative constructor with_two_legs doesn't work because the Human class breaks the Liskov substitution principle by having a different constructor signature. Even if you could get the code to call Animal to build your instance, you'd have problems because you'd end up with an Animal instances and not a Human one (so other methods in Human, if you wrote some, would not be available).
Note that this situation is not that uncommon, many Python subclasses have different constructor signatures than their parent classes. But it does mean that you can't use one class freely in place of the other, as happens with a classmethod that tries to construct instances. You need to avoid those situations.
In this case, you are probably best served by using a default value for the legs argument to the Animal constructor. It can default to 2 legs if no alternative number is passed. Then you don't need the classmethod, and you don't run into problems when you override __init__:
class Animal:
def __init__(self, name, legs=2): # legs is now optional, defaults to 2
self.legs = legs
print(name)
class Human(Animal):
def __init__(self):
super().__init__('Human')
john = Human()
Why am I forced to use threading.Thread.__init__(self) or super(ClassName, self).__init__() when I create a threading.Thread Class?
For example:
class Threader(threading.Thread):
def __init__(self, _fp, _q):
threading.Thread.__init__(self)
self.path = _fp
self.queue = _q
def run(self):
# Do stuff
or
class Threader(threading.Thread):
def __init__(self, _fp, _q):
super(Threader, self).__init__()
self.path = _fp
self.queue = _q
def run(self):
# Do stuff
Both methods work, and do roughly the same thing. However, if I remove either .__init__() methods, I receive in the stack: from thread.start(): thread.__init__() not called.
Shouldn't defining my own def __init__() "replace" the .__init__() method?
I've read this other SO post and that aligned with what I thought, get same stack error though.
Consider this simplified example:
class dog:
def __init__(self):
self.legs = 4
self.sound = 'woof'
class chihuahua(dog):
def __init__(self):
self.sound = 'yip'
# what's missing here?
We've created a subclass of dog, called chihuahua. A user of this class would reasonably expect it to behave like a dog in all default aspects, except the specific one that we have overridden (the sound it makes). But note that, as you have pointed out, the new subclass __init__ replaces the base class __init__. Completely replaces. Unlike C++, the base-class initialization code is not automatically called when a subclass instance is created. Therefore, the line self.legs = 4 never gets run when you create a chihuahua(). As a result, this type of dog is running around without any idea how many legs it has. Hence you could argue it is not a fully-functioning dog, and you shouldn't be surprised if it falls over while trying to perform complex tricks.
As subclass designer you have two options to fix this. The first is to reimplement the self.legs = 4 line explicitly in the subclass. Well, that'll work fine in this example, but it's not a great option in general because it violates the DRY principle even in cases where you do know exactly what code to write and how to maintain it. And in more complex examples (like your Thread subclass), you presumably won't know. Second option: explicitly call the superclass initializer and let it do its thing.
Defining your own __init__ overrides the base class. But what about all the work the base __init__ does to make the thread runnable? All variables and state that it would normally create are missing. Unless you hack all of that in yourself (and why do that?) the thread is of course completely unrunnable.
Not all classes need an __init__ of course, but the vast majority do. Even for the ones that don't, calling __init__ is harmless - it just goes to object.__init__ and future-proofs the child class in the event an implementer decides an __init__ is useful after all.
I frequently do this sort of thing:
class Person(object):
def greet(self):
print "Hello"
class Waiter(Person):
def greet(self):
Person.greet(self)
print "Would you like fries with that?"
The line Person.greet(self) doesn't seem right. If I ever change what class Waiter inherits from I'm going to have to track down every one of these and replace them all.
What is the correct way to do this is modern Python? Both 2.x and 3.x, I understand there were changes in this area in 3.
If it matters any I generally stick to single inheritance, but if extra stuff is required to accommodate multiple inheritance correctly it would be good to know about that.
You use super:
Return a proxy object that delegates
method calls to a parent or sibling
class of type. This is useful for
accessing inherited methods that have
been overridden in a class. The search
order is same as that used by
getattr() except that the type itself
is skipped.
In other words, a call to super returns a fake object which delegates attribute lookups to classes above you in the inheritance chain. Points to note:
This does not work with old-style classes -- so if you are using Python 2.x, you need to ensure that the top class in your hierarchy inherits from object.
You need to pass your own class and instance to super in Python 2.x. This requirement was waived in 3.x.
This will handle all multiple inheritance correctly. (When you have a multiple inheritance tree in Python, a method resolution order is generated and the lookups go through parent classes in this order.)
Take care: there are many places to get confused about multiple inheritance in Python. You might want to read super() Considered Harmful. If you are sure that you are going to stick to a single inheritance tree, and that you are not going to change the names of classes in said tree, you can hardcode the class names as you do above and everything will work fine.
Not sure if you're looking for this but you can call a parent without referring to it by doing this.
super(Waiter, self).greet()
This will call the greet() function in Person.
katrielalex's answer is really the answer to your question, but this wouldn't fit in a comment.
If you plan to go about using super everywhere, and you ever think in terms of multiple inheritance, definitely read the "super() Considered Harmful" link. super() is a great tool, but it takes understanding to use correctly. In my experience, for simple things that don't seem likely to get into complicated diamond inheritance tangles, it's actually easier and less tedious to just call the superclass directly and deal with the renames when you change the name of the base class.
In fact, in Python2 you have to include the current class name, which is usually more likely to change than the base class name. (And in fact sometimes it's very difficult to pass a reference to the current class if you're doing wacky things; at the point when the method is being defined the class isn't bound to any name, and at the point when the super call is executed the original name of the class may not still be bound to the class, such as when you're using a class decorator)
I'd like to make it more explicit in this answer with an example. It's just like how we do in JavaScript. The short answer is, do that like we initiate the constructor using super.
class Person(object):
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, I'm {self.name}")
class Waiter(Person):
def __init__(self, name):
super().__init__(name)
# initiate the parent constructor
# or super(Waiter, self).__init__(name)
def greet(self):
super(Waiter, self).greet()
print("Would you like fries with that?")
waiter = Waiter("John")
waiter.greet()
# Hello, I'm John
# Would you like fries with that?