How can I add class inheritance in a method outside initialization? - python

I want to define a subclass of a class, and I need it to be upgraded to in one of the class' methods, rather than initialized from the very beginning.
The example is a hobby project with Grids and the distances in them.
So I start a Grid class like this:
class Grid:
def __init__(self):
# A grid is a list of lists of cells.
self.grid = self.prepare_grid()
self.configure_cells()
self.maze = None
def __getitem__(self, a_tuple):
x, y = a_tuple
return self.grid[x][y]
def prepare_grid(self):
...
def configure_cells(self):
...
Then I want to add Distance functionality. I was thinking like in a game where you've improved to became a Distance Grid, with methods like:
class DistanceGrid(Grid):
def set_distances(self, root_cell):
...
def path_to(self, goal):
...
Here comes the tricky part. Since I don't want it to be initialized, but rather improved to, I need a method on the parent class to make it a subclass (looks almost recursive, but hopefully it isn't).
from distances import DistanceGrid
class Grid:
...
def upgrade_distance(self, root):
self = type(self, DistanceGrid)
self.set_distances(root)
Can this be done? I'll keep trying.
Thanks

You say, "Since I don't want it to be initialized, but rather improved to, I need a method on the parent class to make it a subclass". Have you ever heard of composition as an alternative to inheritance? It would make it so that you have a method on the parent class to give it a DistanceGrid instance, as one of the class attributes. Something like this:
from distances import DistanceGrid
class Grid:
...
def upgrade_distance(self, root):
self.distance_grid = DistanceGrid()
self.distance_grid.set_distances(root)
The rest of the methods in the Grid class could either act on self.distance_grid if it is a method to be run after the upgrade, or ignore it if it's not needed. Maybe that would work for you?
Edit: You could also make 3 classes; 1-DistanceGrid, 2-Grid, 3-Choice, where the Choice class is the only one you create, it inherits from both of the other classes, and you decide which methods you want to call as you go.

Related

Python - Propagating added base class functionalty to subclasses

Say I am using a shape-drawing framework with the following classes:
class Shape(ABC):
movable: False
#abstractmethod
def movePoint(pointId, newX, newY): pass
class Rect(Shape):
aspectLocked: False
# Implement abstract function
def movePoint(pointId, newX, newY): pass
class Hexagon(Shape): pass
# ...
I want to use Rect, Hexagon, etc. in my code, but I want each to have a fill() method. However, fill() can work at the Shape level, so I end up doing this:
def _shapeFill(self):
pass
class MyRect(Rect):
def fill(self):
return _shapeFill(self)
# Same procedure for Hexagon, etc.
I can also do
for shape in [Rect, Hexagon]:
shape.fill = _shapeFill
But editors like PyCharm don't recognize fill() as a class method and I don't know if this solution is robust.
Basically, I want to extend Shape AND have that extended method available in the Rect class without having to redefine Rect. Is there a pythonic solution?
Bonus points if someone can tell me the technical name for this, since I didn't know what term to Google. Thanks!
You can just attach it to the ABC:
Shape.fill = _shapefill
If you want to play more nicely with IDEs and code analysis, you could define your extra methods in a mixin class which you inherit from in custom shape classes:
class ShapeMixin:
def fill(self):
pass
class MyRect(Rect, ShapeMixin):
pass
This is basically your first solution, but expressed a little more cleanly.

Pythonic multiple inheritance to generate collections of custom classes

I've got two class trees in my Python code:
BaseComponent BaseSeries
/ | \ |
Resistor Capacitor Inductor ESeries
The BaseSeries class tree implements preferred numbers such as the E-series, and generates sets of values between a pair of powers (e.g. [1.0, 2.2, 4.7, 10, 22, 47, 100, 220, 470] for the E3 series with exponents between 1 to 3).
By default, ESeries and any other instance of BaseSeries creates sequences of float objects. I'd like to use these classes to instead create sequences of Resistor, Capacitor and Inductor objects. Ideally, the individual Resistor, Capacitor, Inductor and ESeries classes would remain usable on their own (i.e. not rely on methods being implemented by other classes).
This sounds like a job for multiple inheritance, but I'm a bit confused about how best to implement this in Python (3). Ideally I'd like to just define something like:
class ResistorESeries(Resistor, ESeries):
pass
class CapacitorESeries(Capacitor, ESeries):
pass
class InductorESeries(Inductor, ESeries):
pass
in order to create classes that yield sequences of resistors, capacitors and inductors, but I don't know how best to tell BaseSeries instances to create objects of type Resistor, Capacitor and Inductor. I can think of two ways, but I can't decide which one is best, and I have a feeling there is a simpler, more Pythonic way that I'm missing:
have BaseSeries contain a property or variable pointing to the element type (e.g. Resistor) set either by the constructor, a class variable in the child class (e.g. Resistor.ELEMENT_TYPE = Resistor) or with an abstract property provided by the child class:
class BaseSeries(object):
...
def elements(self):
# loop over numbers in this series
for v in self.values():
yield self.element_type(v)
#property
#abc.abstractmethod
def element_type(self):
return NotImplemented
class ESeries(BaseSeries):
....
class BaseComponent(object):
...
#property
def element_type(self):
return self
class Resistor(BaseComponent):
...
class ResistorESeries(Resistor, ESeries):
# now BaseSeries' `element_type` property is provided by `BaseComponent`
pass
This would mean ESeries cannot be used on its own as a concrete object, as it does not implement this property/variable, which is not ideal.
use self when creating elements in BaseSeries, where self will, as long as Resistor is earlier in the method resolution order, refer to the desired element:
class BaseSeries(object):
...
def elements(self):
# loop over numbers in this series
for v in self.values():
# self here would refer to `Resistor` in
# `ResistorESeries` instances
yield self(v)
class ESeries(BaseSeries):
....
class BaseComponent(object):
...
class Resistor(BaseComponent):
...
class ResistorESeries(Resistor, ESeries):
pass
This has the downside that, in instances of ESeries without being used as a mix-in, self will refer to itself, which does not support the correct __init__ signature.
So, does anyone have an idea of how best to do this in a Pythonic way, with maximum ability to reuse classes on their own?
You are likely mixing some concepts there - notably "instances" and "classes" - your example calls that do self(v) are perplexing.
I can't see from your design why the classes on the BaseComponent tree would need to be inherited along the BaseSeries tree: can't the component type simply be an attribute on the BaseSeries class?
It is simply a matter of using a class attribute, and in the code suggested on your first attempt, use a prosaic if statement.
class BaseSeries:
component = None
def elements(self):
# loop over numbers in this series
for v in self.values():
yield self.component(v) if self.component else v
class Capacitor(BaseComponent):
...
class CapacitorSeries(BaseSeries):
component = Capacitor
If you think you need multiple inheritance, you can just go for your idea of using a property, and use the same "if" statement there. But if both hierarchies are that ortogonal, I don't see why force the use of multiple inheritance, just because the language permits it.
Maybe you prefer to have it the other way around: a factory method on the component tree that will take an ESeries class as input, and extract the values from that ...
Anyway, you are not making clear the disctinction of classes and instances there. Do you need to have a way to produce several subclasses of
"CapacitorESeries", each class for a different value?
Or would you need just instances of "Capacitors", each for a different value produced on the series?
class BaseComponent:
...
#classmethod
def series_factory(self, series):
for value in series.values():
yield self.__class__(value)
Of course, there could be use cases for really needing classes for everything you claim, including the factories for series of classes, but your use of self as a callable in your snippets suggests that your stance on that is not that solid.
In that case, first, you need all methods to make proper use of super. even if they ar enot supposed to exist across both hierarchies, using super will just call the proper method on the superclasses. But for methods like __init__ this is just needed.
If you design a proper __init__ method using super, and always using named parameters, your second strategy will work out of the box, just fixing the instantiating call (to something other than self(v). Using named parameters and passing the remaining parameters to super will ensure each class in the tree consumes what it needs of those parameters - and when Python gets to the root of both your hierarchies and calls object's __init__, no parameter is remaining,
class BaseSeries:
def __init__(self, value_min, value_max, **kwargs):
self.value_min = value_min
selfvalue_max = value_max
super().__init__(**kwargs)
def elements(self):
# loop over numbers in this series
for v in self.values():
yield self.__class__(value_min = self.value_min, value_max=self.value_max, value=value)
class BaseComponent:
def __init__(self, value, **kwargs):
self.value = value
...
class CapacitorESeries(Capacitor, Eseries):
pass

Python - inheritance and method overriding

I have two classes, one inheriting from the other. Let's call them Parent and Child.
Both of the objects created from those classes should use function funA, which looks like below
funA():
X = another_function()
Y = # some value
X.append(Y)
# do other computations
For both classes, function funA looks almost the same, except function another_function(), which computes in a different way the list X for the Parent and differently for the Child. Of course, I know that I can override function funA in the Child class, but since this function is very long and does several operations, copy-pasting it would be a little bit a waste. On the other hand - I have to distinguish that the Parent class should use one version of another_function() and the Child class should use the second version of another_function(). Is is maybe possible to point which version of another_function (let's call them another_function_v1 and another_function_v2) should be used by each class or the only solution if to override the whole function funA?
Your post is not quite clear but I assume funA is a method of Parent. If yes, just add some another_method method calling the right function:
class Parent(object):
def another_method(self):
return another_function_v1()
def funA(self):
X = self.another_method()
Y = # some value
X.append(Y)
# do other computations
class Child(Parent):
def another_method(self):
return another_method_v2()
nb if funA is a classmethod you will want to make another_method a classmethod too...
I don't know where your another_functions come. I suppose they are normal functions, which can be imported and used
class Parent(object):
another_function = another_function_v1
def funA(self):
X = self.another_function()
Y = # some value
X.append(Y)
# do other computations
class Child(Parent):
another_function = another_function_v2

Lateral association between an object and a function assigned to variable

I have objects defined that are evolving under a subroutine, and under subsubroutines. And I want to probe the status of these variables via probes.
For example, lets call this class drunk.
class drunk (object):
def __init__(self):
self.position = 0
self.probability = 0.5
def take_a_step():
# code that will make the drunkard change its position
Then, I may generate many drunkards and put them into a class crowd.
class crowd (object):
def __init__(self):
self.inidividuals = num.array([])
I would like to create a "probe" object that can be assigned into any of those objects, but I have implementation problems.
class probe (object):
def __init__(self):
self.function = None
self.data = num.array([])
I want to assign probes to any drunkard, a probe will extract any information from a crowd, or a drunk, that is defined in a function residing in probe.function.
But as far as I am concerned, I can assign probes by putting them into a list within these classes, and call them by relating to the functions within the methods of the classes crowd and drunk.
But in order to do this,
probe_mean = probe()
def probe_function():
#
#
#
probe_mean.function = probe_function()
But since I want to refer to a variable within a class that the function will be within the list of, It seems that I must define the function as
But in order to do this,
probe_mean = probe()
def probe_function(probed):
return probed.position.mean()
probe_mean.function = probe_function(drunk_53)
drunk_53.probes.append(probe_mean)
I have a feeling from the fact that these to objects should refer to each other in order for this to work, this is not he way it should be.
I thought that there must be a way to deal with this without re-introducing drunk_53 to the function, something like a super(), that will enable a vertical association.
I'm not experienced in OOP, so I'm asking for the most suitable way (Pythonic, elegant etc.) to do this. What are your opinions? What approach would you take?

Is there a benefit to defining a class inside another class in Python?

What I'm talking about here are nested classes. Essentially, I have two classes that I'm modeling. A DownloadManager class and a DownloadThread class. The obvious OOP concept here is composition. However, composition doesn't necessarily mean nesting, right?
I have code that looks something like this:
class DownloadThread:
def foo(self):
pass
class DownloadManager():
def __init__(self):
dwld_threads = []
def create_new_thread():
dwld_threads.append(DownloadThread())
But now I'm wondering if there's a situation where nesting would be better. Something like:
class DownloadManager():
class DownloadThread:
def foo(self):
pass
def __init__(self):
dwld_threads = []
def create_new_thread():
dwld_threads.append(DownloadManager.DownloadThread())
You might want to do this when the "inner" class is a one-off, which will never be used outside the definition of the outer class. For example to use a metaclass, it's sometimes handy to do
class Foo(object):
class __metaclass__(type):
....
instead of defining a metaclass separately, if you're only using it once.
The only other time I've used nested classes like that, I used the outer class only as a namespace to group a bunch of closely related classes together:
class Group(object):
class cls1(object):
...
class cls2(object):
...
Then from another module, you can import Group and refer to these as Group.cls1, Group.cls2 etc. However one might argue that you can accomplish exactly the same (perhaps in a less confusing way) by using a module.
I don't know Python, but your question seems very general. Ignore me if it's specific to Python.
Class nesting is all about scope. If you think that one class will only make sense in the context of another one, then the former is probably a good candidate to become a nested class.
It is a common pattern make helper classes as private, nested classes.
There is another usage for nested class, when one wants to construct inherited classes whose enhanced functionalities are encapsulated in a specific nested class.
See this example:
class foo:
class bar:
... # functionalities of a specific sub-feature of foo
def __init__(self):
self.a = self.bar()
...
... # other features of foo
class foo2(foo):
class bar(foo.bar):
... # enhanced functionalities for this specific feature
def __init__(self):
foo.__init__(self)
Note that in the constructor of foo, the line self.a = self.bar() will construct a foo.bar when the object being constructed is actually a foo object, and a foo2.bar object when the object being constructed is actually a foo2 object.
If the class bar was defined outside of class foo instead, as well as its inherited version (which would be called bar2 for example), then defining the new class foo2 would be much more painful, because the constuctor of foo2 would need to have its first line replaced by self.a = bar2(), which implies re-writing the whole constructor.
You could be using a class as class generator. Like (in some off the cuff code :)
class gen(object):
class base_1(object): pass
...
class base_n(object): pass
def __init__(self, ...):
...
def mk_cls(self, ..., type):
'''makes a class based on the type passed in, the current state of
the class, and the other inputs to the method'''
I feel like when you need this functionality it will be very clear to you. If you don't need to be doing something similar than it probably isn't a good use case.
There is really no benefit to doing this, except if you are dealing with metaclasses.
the class: suite really isn't what you think it is. It is a weird scope, and it does strange things. It really doesn't even make a class! It is just a way of collecting some variables - the name of the class, the bases, a little dictionary of attributes, and a metaclass.
The name, the dictionary and the bases are all passed to the function that is the metaclass, and then it is assigned to the variable 'name' in the scope where the class: suite was.
What you can gain by messing with metaclasses, and indeed by nesting classes within your stock standard classes, is harder to read code, harder to understand code, and odd errors that are terribly difficult to understand without being intimately familiar with why the 'class' scope is entirely different to any other python scope.
A good use case for this feature is Error/Exception handling, e.g.:
class DownloadManager(object):
class DowndloadException(Exception):
pass
def download(self):
...
Now the one who is reading the code knows all the possible exceptions related to this class.
Either way, defined inside or outside of a class, would work. Here is an employee pay schedule program where the helper class EmpInit is embedded inside the class Employee:
class Employee:
def level(self, j):
return j * 5E3
def __init__(self, name, deg, yrs):
self.name = name
self.deg = deg
self.yrs = yrs
self.empInit = Employee.EmpInit(self.deg, self.level)
self.base = Employee.EmpInit(self.deg, self.level).pay
def pay(self):
if self.deg in self.base:
return self.base[self.deg]() + self.level(self.yrs)
print(f"Degree {self.deg} is not in the database {self.base.keys()}")
return 0
class EmpInit:
def __init__(self, deg, level):
self.level = level
self.j = deg
self.pay = {1: self.t1, 2: self.t2, 3: self.t3}
def t1(self): return self.level(1*self.j)
def t2(self): return self.level(2*self.j)
def t3(self): return self.level(3*self.j)
if __name__ == '__main__':
for loop in range(10):
lst = [item for item in input(f"Enter name, degree and years : ").split(' ')]
e1 = Employee(lst[0], int(lst[1]), int(lst[2]))
print(f'Employee {e1.name} with degree {e1.deg} and years {e1.yrs} is making {e1.pay()} dollars')
print("EmpInit deg {0}\nlevel {1}\npay[deg]: {2}".format(e1.empInit.j, e1.empInit.level, e1.base[e1.empInit.j]))
To define it outside, just un-indent EmpInit and change Employee.EmpInit() to simply EmpInit() as a regular "has-a" composition. However, since Employee is the controller of EmpInit and users don't instantiate or interface with it directly, it makes sense to define it inside as it is not a standalone class. Also note that the instance method level() is designed to be called in both classes here. Hence it can also be conveniently defined as a static method in Employee so that we don't need to pass it into EmpInit, instead just invoke it with Employee.level().

Categories

Resources