I am confused about the right approach I should take
I am creating a sort of game and in this game the main character has accessories.
So I was thinking about an abstract class named Item. Inheriting from Item are also abstract class such as Glasses, Shirt etc...
The reason I think it should be abstract is that I never create glasses for example, I create an instance of "Green Shades". Green Shades is also a class and I think it should inherit from glasses of course.
I was thinking about making Item an abstract class and also Glasses an abstract class for example but they have a factory method that generates the types of glasses(Green Shades, Blue Shades and so on).
Each Item has a worth property (basic or rare).
I've started to write something but I am getting confused on the implementation details.
Item:
from enum import Enum
from abc import ABCMeta, abstractmethod
class Worth(Enum):
BASIC = 0
RARE = 1
class Item(object):
__metaclas__ = ABCMeta
def __init__(self, worth):
self.worth = worth
#property
#abstractmethod
def type_factory(self,type):
pass
Glasses and an example of a glasses:
from abc import ABCMeta, abstractmethod
import importlib
Enums = importlib.import_module('Enums')
Item = importlib.import_module('Item')
class Glasses(Item):
__metaclas__ = ABCMeta
def __init__(self,worth,type):
super().__init__(worth)
# self.type = self.type_factory()
#property
#abstractmethod
def type_factory(self,type):
if type == Enums.GlassesType.BLACK_SHADES:
return BlackShades()
# so on..
class BlackShades(Glasses):
def __init__(self,worth):
super().__init__(worth)
What would be the best way to do it? Is there a better example of a factory I should use? Maybe it will be better to use type class creation?
To clarify: I am not looking just to improve this code. I wouldn't mind implementing it from scratch using the right way to do so, which I am not sure what it is due to my lack of experience in Python.
Thanks
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.
Is there a way to declare an abstract instance variable for a class in python?
For example, we have an abstract base class, Bird, with an abstract method fly implemented using the abc package, and the abstract instance variable feathers (what I'm looking for) implemented as a property.
from abc import ABCMeta, abstractmethod
class Bird(metaclass=ABCMeta):
#property
#abstractmethod
def feathers(self):
"""The bird's feathers."""
#abstractmethod
def fly(self):
"""Take flight."""
The problem is that Eagle, a class derived from Bird, is required to have feathers implemented as a property method. So the following is not an acceptable class, but I'd like it to be
class Eagle(Bird):
def __init__(self):
self.feathers = 'quill'
def fly(self):
print('boy are my arms tired')
There might be a problem since the requirement is on the instance itself, and really after its instantiation, so I don't know if things like the abc package will still work.
Are there some standard ways of handling this?
The abc system doesn't include a way to declare an abstract instance variable. The code that determines whether a class is concrete or abstract has to run before any instances exist; it can inspect a class for methods and properties easily enough, but it has no way to tell whether instances would have any particular instance attribute.
The closest thing is probably a variable annotation:
class Bird(metaclass=ABCMeta):
feathers : str
...
abc won't do anything with that annotation, but it at least expresses to readers and static type checkers that instances of Bird are supposed to have a feathers instance variable. (Whether static type checkers will understand that this instance variable is supposed to come from subclasses, I don't know.)
Something simple like the following can work, using a common property:
class Bird(object):
#property
def feathers(self):
try:
return self._feathers
except AttributeError:
raise WhateverError('No feathers') # maybe obfuscate inner structure
class Eagle(Bird):
def __init__(self):
self._feathers = 'quill'
>>> Bird().feathers
WhateverError: No feathers
>>> Eagle().feathers
'quill'
I'm trying to figure out how to ensure that a method of a class inheriting from an ABC is created using the appropriate decorator. I understand (hopefully) how ABCs work in general.
from abc import ABCMeta, abstractmethod
class MyABC(metaclass=ABCMeta):
#abstractmethod
def my_abstract_method(self):
pass
class MyClass(MyABC):
pass
MyClass()
This gives "TypeError: Can't instantiate abstract class MyClass with abstract methods my_abstract_method". Great, makes sense. Just create a method with that name.
class MyClass(MyABC):
def my_abstract_method(self):
pass
MyClass()
Boom. You're done. But what about this case?
from abc import ABCMeta, abstractmethod
class MyABC(metaclass=ABCMeta):
#property
#abstractmethod
def my_attribute(self):
pass
class MyClass(MyABC):
def my_attribute(self):
pass
MyClass()
The MyClass() call works even though my_attribute is not a property. I guess in the end all ABCs do is ensure that a method with a given name exists. Thats it. If you want more from it, you have to look at MyABC's source code and read the documentation. The decorators and comments there will inform you of how you need to construct your sub-class.
Do I have it right or am I missing something here?
You're correct that ABCs do not enforce that. There isn't a way to enforce something like "has a particular decorator". Decorators are just functions that return objects (e.g., property returns a property object). ABCMeta doesn't do anything to ensure that the defined attributes on the class are anything in particular; it just makes sure they are there. This "works" without errors:
class MyABC(metaclass=ABCMeta):
#abstractmethod
def my_abstract_method(self):
pass
class MyClass(MyABC):
my_abstract_method = 2
MyClass()
That is, ABCMeta doesn't even ensure that the abstract method as provided on the subclass is a method at all. There just has to be an attribute of some kind with that name,
You could certainly write your own metaclass that does more sophisticated checking to ensure that certain attributes have certain kinds of values, but that's beyond the scope of ABCMeta.
The title is pretty much self explanatory, but I think this is better explained with an example.
class Dog():
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
def get_color(self):
return body_color()
class personality_1():
def get_happiness(self):
return happiness_with_owner()
def get_sadness(self):
return sadness()
## A lot more personality methods here
class SocialDog(Dog):
# Override regular method
def get_color(self):
return face_color()
# I want to override the personality 1 class but not completely, just one method
class personality_2(>>>How to inherit from personality_1?<<<):
# Now, I would like to override just one method of personality 1:
def get_happiness(self):
return happiness_with_others()
Hopefully the logic is correct. I was trying to use super() with no success. Hopefully I can find a solution without using an explicit call to the parent class.
Any thoughts?
Thanks in advance!
To inherit from the class you specified, according to the code you provided, all that is required is to define the class personality_2 like this:
class SocialDog(Dog):
#...
class personality_2(Dog.personality_1):
#...
Now, as for your problem when trying to use super(), this might be because your base classes of Dog and Dog.personality_1 do not inherit from the python default class object which is required in order to use the super() method. See this answer for details. If that is what you are after, all you need to do is modify your class declarations for Dog and Dog.personality_1 (or whatever they ultimately derive from) to the following:
class Dog(object):
#...
class personality_1(object):
#...
Then you can treat SocialDog.personality_2 just like any other subclass. If you are using python 2, remember when using super() that you need to use the fully qualified name:
super(SocialDog.personality_2, self).super_class_method()
super(SocialDog.personality_2, self).super_class_field
Use the name of the outer class to reach the inner class:
class SocialDog(Dog):
class personality_2(Dog.personality_1):
# ...
That said, this is a very weird thing you're doing, hiding the personality classes inside the dog classes, then using them outside...
If a personality is that tightly coupled to a specific class like Dog or SocialDog, what makes personality_2 think it's safe to mess with the behaviour of personality_1? In fact, the personality methods should probably be Dog or SocialDog methods instead.
Or, if it doesn't really matter which dog gets which personality, why not leave the personality classes up at the module level, where they can be instantiated and inherited like any other class? Your various Dog-derived classes would then take an optional personality argument when created:
class WolfPersonality(DogPersonality):
# ...
class Wolf(Dog):
def __init__(self, personality=None):
if personality is None:
personality = WolfPersonality()
self.personality = personality
# ...
# Later...
wolf = Wolf()
wolf_puppy = Wolf(FriendlyDogPersonality())
Ideally I would like to extend an instance of PIL's image class to include some custom methods; Image doesn't support this however, so I need to change tack. Delegation seems to be the most conventional alternative, but before I stumbled upon this aspect of python I had toyed with the idea of creating my custom class with an attribute that functioned as an instance of the PIL Image class. I've not seen this done anywhere else, but is this essentially the same thing as delegation?
import Image
MyImageClass():
def __init__(self, filepath):
self.attrA = ...
self.attrB = ...
self.attrc = ...
self.img = Image.open(filepath)
def method_A(self):
...
def method_B(self):
im = MyImageClass('/path/to/png')
im.self.img.thumbnail((100,100))
Sure. This is no different than:
class Foo(object):
def __init__(self):
self.bar = 'test'
im = Foo()
print im.bar.upper()
Notice that it is im.bar, not im.self.bar.
self in __init__ is the same as im so self.bar in __init__ is the same as im.bar outside of it.
Of course instances can be attributes of classes. But you say that you want an enhanced Image class - so extend Image:
#take this with a grain of salt - I didn't test the code
from PIL.Image import Image
MyImageClass(Image):
def __init__(self):
super(MyImageClass, self).__init__()
self.init_some = 'custom_stuff'
def method_A(self):
...
def method_B(self):
im = MyImageClass.open('/path/to/png')
im.thumbnail((100,100))
Update
As OP pointed out Image isn't designed to be subclassed by application code. Hence my example is just a general example for inheritance.
In Python, the boundaries beween delegation, composition, aggregation, and other has a repationships are pretty blurry, as they all tend to share the same syntax, and with garbage collection there are no worries about ownership. What you call it will mainly depend on what you do with the objects, i.e. if MyImageClass.method_A just calls self.img.method_A(), etc., it would be delegation.
I'm pretty sure you have seen this before, as every value in Python – including values of all attributes – is an instance of some type.
If your class is an Image, you're looking for inheritance. Your class should be a subclass of Image.