What is the best to extend functionality of a Library class method - python

I have a library code that provides class and that class is expected to be a subclass of my frameworks classes.
Now I want to extend one of the functionalities of a library class method, here I can think of 2 approaches:
create a new class with subclass library class then override library class method in a new class
create Mixins override the functionality of the library class method and inherit that as well
Here is a coded way of my above 2 theoretical approaches.
approach 1:
class Library:
def method_one(self):
return {"method_one": "one"}
def method_two(self):
return {"method_two": "two"}
class FrameworkOne(Library):
def method_one(self):
method = super().method_one()
method["label"] = self.__class__.__name__
return method
class FrameworkTwo(Library):
def method_one(self):
method = super().method_one()
method["label"] = self.__class__.__name__
return method
approach 2:
class MixinFramework:
def method_one(self):
method = super().method_one()
method["label"] = self.__class__.__name__
return method
class FrameworkOne(MixinFramework, Library):
pass
class FrameworkTwo(MixinFramework, Library):
pass
another way I can think of is to create another Baseclass which will inherit Library class and override method_one in Base class and inherit Baseclass in all Framework classes instead of Library class
approach one seems to code redundancy issue and approach two seems to me like narrow down
is there any better approach or a decorator way that I can put on to each class where I want to extend the functionality of method_one
Please suggest.

Related

How to pass arguments to overridden functions with different interface?

The situation is: An abstract base class defines a set of common actions, while leaving a bunch of specialized actions to subclasses.
from abc import ABC,abstractmethod
class Common(ABC):
def __init__(self,ord_obj):
self.ord_obj = ord_obj
self.abs_obj = self.generate_abs_obj(?)
#abstractmethod
def generate_abs_obj(self):
# Will be implemented in subclasses
pass
def common_operation(self):
return self.ord_obj + self.abs_obj
class specialize_1(Common):
def __init__(self):
super().__init__()
def generate_abs_obj(self,param_1):
# do something
return 25
class specialize_2(Common):
def __init__(self):
super().__init__()
def generate_abs_obj(self,param_1,param_2):
# do something
return param_1+param_2
As shown above, abs_obj is an object generated by an abstract method and initialized in base class __init__. It will be used in the base class by an ordinary method. However, the generate_abs_obj in subclasses have different interfaces. How do I call super().__init__() with different parameters?
The overall approach that you are using seems to be entirely not-pythonic. I highly recommend watching Raymond Hettinger explain Super and Pythonic inheritance in this talk

Annotate subclass's method?

Suppose I have a Mixin class Mixin, and a method a in this class uses another method
b which will be in another Base class. I want to annotate b in class Mixin so that I can take the advantages of inspection.
The real usage is multiple inherition. I create a mixin for tornado.web.RequestHandler, and the subclass could inherit both RequestHandler and Mixin to get some useful functions.
As far as I know, I can annotate b as Callable, but I cannot annotate its signature.
class Base
def b():
# do something
class Mixin:
b: Callable # not enough, losing signature.
#b: RequestHandler.b # not work, still losing signature.
def a():
# call b here.
class subclass(Base, Mixin):
pass
BTW, I'm using Pycharm.

Python mixin with dynamic method names

Supposing I have the following classes:
class SomeMixin:
def apply(self):
pass
class Foo(SomeMixin):
pass
class Bar(SomeMixin):
pass
How do I implement SomeMixin so that the attached method apply becomes apply_foo in Foo and apply_bar in Bar? The methods in the mixin follows a generic algorithm, but the generated names matter to the framework I'm using.
You wouldn't do that in the mixin, but in the concrete classes themselves. Just define the methods so that they call apply directly.
class Foo(SomeMixin):
def apply_foo(self):
return self.apply()
class Bar(SomeMixin):
def apply_bar(self):
return self.apply()

Extending a class hierarchy in Python

I have a class hierarchy in a module that I want to extend.
The module to be extended looks something like this.
Module foo:
class bar(object): pass
class spam(bar): pass
class eggs(bar): pass
Now I want to extend these classes:
class my_bar(foo.bar):
def new_func(): pass
class my_spam(foo.spam): pass
class my_eggs(foo.eggs): pass
Doing so, a new function new_func() in my_bar would not be available in a my_spam instance using
my_spam_instance.new_func()
What is the best ("most pythonic") way to achieve this? I thought of multiple inheritance, like this:
class my_bar(foo.bar): pass
class my_spam(foo.bar, my_bar): pass
class my_eggs(foo.eggs, my_bar): pass
Though I never really used it before and I am not sure this is the best way.
You don't even need to inherit my_bar from bar
pythonic will be adding Mixin, which is actually a base class, but not inherited
class NewFuncMixin():
def new_func(): pass
And add it to new classes
class my_bar(foo.bar, NewFuncMixin): pass
class my_spam(foo.spam, NewFuncMixin): pass
class my_eggs(foo.eggs, NewFuncMixin): pass
What about a mixin class? The pattern is
class My_mixin( object):
def new_func(self): pass
class My_spam( My_mixin, foo.spam): pass
class My_eggs( My_mixin, foo.eggs): pass
mixins should inherit from object, and go on the left of the inheritance list so that the mixin class methods get name priority. Within the mixin you can then wrap any method of the superclass:
class My_mixin( object):
def bar_method( self):
# stuff
bar_result = super( My_mixin, self).bar_method()
# more stuff
return bar_result # or my_result based on bar_result
You can of course completely override the method instead of wrapping it.

Robot Framework keywords and Inheritance

I have a library of keywords. I have a few classes and subclasses, but I'm having an issue with inheritance and keywords being double-defined. For example:
MyLib.py
class Class1:
def __init__(self):
pass
def do_something_generic(self):
#do stuff that is generic to all subclasses
pass
class Subclass1(Class1):
def __init__(self):
pass
def do_something_specific_to_subclass1(self):
#something specific
pass
class Subclass2(Class1):
def __init__(self):
pass
def do_something_specific_to_subclass2(self):
#something specific
pass
The specific keywords work fine, but when I try to call Do Something Generic I get Multiple keywords with name 'Do Something Generic' found. I can fully qualify the library name with MyLib.Class1.Do Something Generic, but is there any way to define Do Something Generic to always refer to the superclass, since the method is only defined there and is simply inherited by the subclasses?
From Robot Framework User Guide
When the static library API is used, Robot Framework uses reflection to find out what public methods the library class or module implements.
It will exclude all methods starting with an underscore,
and with Java libraries also methods that are implemented only in java.lang.Object are ignored.
All the methods that are not ignored are considered keywords.
Have you considered adding helper base class with a _do_something_generic function? You can exclude it from __all__ list. Then use the inheritance to expose keywords from the base class in Class1.
MyLibrary.py:
__all__ = ['Class1', 'Subclass1', 'Subclass2']
class BaseClass:
def _do_something_generic(self):
pass
class Class1(BaseClass):
def __init__(self):
pass
def do_something_generic(self):
return self._do_something_generic()
class Subclass1(BaseClass):
def __init__(self):
pass
def do_something_specific_to_subclass1(self):
a = self._do_something_generic()
return (a, 3)
class Subclass2(BaseClass):
def __init__(self):
pass
def do_something_specific_to_subclass2(self):
#something specific
pass
I think the best solution is to simply move do_something_generic to a separate class, so that your base class only has helper functions and no public keywords:
class Class1:
def __init__(self):
pass
class Subclass0(Class1):
def do_something_generic(self):
#do stuff that is generic to all subclasses
pass
While it might be possible to solve this with something exotic like using __slots__ or __getattr__, or modifying self.__dict__, it's probably not worth the trouble.

Categories

Resources